home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / comm / mail / YAM23src.lha / Source / YAM_WR.c < prev    next >
C/C++ Source or Header  |  2001-05-14  |  109KB  |  2,436 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
  5.  Copyright (C) 2000-2001 by YAM Open Source Team
  6.  
  7.  This program is free software; you can redistribute it and/or modify
  8.  it under the terms of the GNU General Public License as published by
  9.  the Free Software Foundation; either version 2 of the License, or
  10.  (at your option) any later version.
  11.  
  12.  This program is distributed in the hope that it will be useful,
  13.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  GNU General Public License for more details.
  16.  
  17.  You should have received a copy of the GNU General Public License
  18.  along with this program; if not, write to the Free Software
  19.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  
  21.  YAM Official Support Site :  http://www.yam.ch
  22.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  23.  
  24.  $Id: YAM_WR.c,v 1.29.2.1 2001/05/14 19:58:53 laursen Exp $
  25.  
  26. ***************************************************************************/
  27.  
  28. #include "YAM.h"
  29.  
  30. /* local protos */
  31. LOCAL void WR_ComposeMulti(FILE*, struct Compose*, char*);
  32. LOCAL struct WritePart *BuildPartsList(int);
  33. LOCAL char *GetDateTime(void);
  34. LOCAL char *NewID(BOOL);
  35. LOCAL int WhichEncodingForFile(char*, char*);
  36. LOCAL int WR_CharOut(char);
  37. LOCAL char *firstbad(char*);
  38. LOCAL void PutQP(unsigned char, FILE*);
  39. LOCAL void HeaderFputs(char*, FILE*);
  40. LOCAL void EmitRcptField(FILE*, char*);
  41. LOCAL void EmitRcptHeader(FILE*, char*, char*);
  42. LOCAL void FPutsQuoting(char*, FILE*);
  43. LOCAL void WriteCtypeNicely(FILE*, char*);
  44. LOCAL void WriteContentTypeAndEncoding(FILE*, struct WritePart*);
  45. LOCAL void WR_WriteUIItem(FILE*, int*, char*, char*);
  46. LOCAL void WR_WriteUserInfo(FILE*);
  47. LOCAL void EncodePart(FILE*, struct WritePart*);
  48. LOCAL BOOL WR_CreateHashTable(char*, char*, char*);
  49. LOCAL void WR_AddTagline(FILE*);
  50. LOCAL void WR_WriteSignature(FILE*, int);
  51. LOCAL void WR_Anonymize(FILE*, char*);
  52. LOCAL char *WR_GetPGPId(struct Person*);
  53. LOCAL char *WR_GetPGPIds(char*, char*);
  54. LOCAL BOOL WR_Bounce(FILE*, struct Compose*);
  55. LOCAL BOOL WR_SaveDec(FILE*, struct Compose*);
  56. LOCAL void WR_EmitExtHeader(FILE*, struct Compose*);
  57. LOCAL void WR_ComposeReport(FILE*, struct Compose*, char*);
  58. LOCAL void SetDefaultSecurity(struct Compose*);
  59. LOCAL BOOL WR_ComposePGP(FILE*, struct Compose*, char*);
  60. LOCAL char *WR_TransformText(char*, int, char*);
  61. LOCAL void WR_SharedSetup(struct WR_ClassData*, int);
  62. LOCAL APTR MakeAddressField(APTR*, char*, APTR, int, int, BOOL);
  63. LOCAL struct WR_ClassData *WR_NewBounce(int);
  64.  
  65.  
  66. /***************************************************************************
  67.  Module: Write
  68. ***************************************************************************/
  69.  
  70. /*** Translate aliases ***/
  71. /// WR_ResolveName
  72. //  Looks for an alias, email address or name in the address book
  73. char FailedAlias[SIZE_NAME];
  74. int WR_ResolveName(int winnum, char *name, char **adrstr, BOOL nolists)
  75. {
  76.    int hits = 0, i, retcode;
  77.    struct ABEntry *ab;
  78.    struct MUI_NListtree_TreeNode *tn, *tn2;
  79.  
  80.    stccpy(FailedAlias, name, SIZE_NAME);
  81.    AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, name, ASM_ALIAS|ASM_USER|ASM_LIST|ASM_GROUP, &hits, &tn);
  82.    if (hits > 1) return 3; // multiple matches
  83.    if (!hits)
  84.    {
  85.       AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, name, ASM_REALNAME|ASM_USER|ASM_LIST|ASM_GROUP, &hits, &tn);
  86.       if (hits > 1) return 3;
  87.       else if (!hits)
  88.       {
  89.           AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, name, ASM_ADDRESS|ASM_USER|ASM_LIST|ASM_GROUP, &hits, &tn);
  90.                 if (hits > 1) return 3;
  91.         else
  92.         {
  93.           if (!hits && strchr(name, '@'))
  94.             {
  95.                       char *p = NULL;
  96.                       struct Person pe;
  97.  
  98.                       ExtractAddress(name, &pe);
  99.  
  100.                       if (pe.Address[0]) p = strchr(pe.Address, '@'); // is it an email address?
  101.  
  102.                   if (!p[1]) strcpy(p, strchr(C->EmailAddress, '@'));
  103.                   if (**adrstr) *adrstr = StrBufCat(*adrstr, ", ");
  104.                   *adrstr = StrBufCat(*adrstr, BuildAddrName2(&pe));
  105.                 return 0;     // if it is an email we return without an error because finding an entry for an email isn`t a must
  106.               }
  107.           else if (!hits) return 2;
  108.         }
  109.       }
  110.    }
  111.  
  112.    ab = tn->tn_User;
  113.  
  114.    switch (ab->Type)
  115.    {
  116.       case AET_USER:
  117.          if (**adrstr) *adrstr = StrBufCat(*adrstr, ", ");
  118.          *adrstr = StrBufCat(*adrstr, BuildAddrName(ab->Address, ab->RealName));
  119.          break;
  120.       case AET_LIST:
  121.          if (nolists) return 4;
  122.          if (winnum >= 0) if ((ab->Address[0] || ab->RealName[0]) && !G->WR[winnum]->ListEntry) G->WR[winnum]->ListEntry = ab;
  123.          if (ab->Members)
  124.          {
  125.             char *ptr;
  126.             for (ptr = ab->Members; *ptr; ptr++)
  127.             {
  128.                char *nptr = strchr(ptr, '\n');
  129.                if (nptr) *nptr = 0; else break;
  130.                retcode = WR_ResolveName(winnum, ptr, adrstr, nolists);
  131.                *nptr = '\n'; ptr = nptr;
  132.                if (retcode) return retcode;
  133.             }
  134.          }
  135.          break;
  136.       case AET_GROUP:
  137.          if (nolists) return 4;
  138.          for (i=0; ; i++)
  139.             if ((tn2 = (struct MUI_NListtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_NListtree_GetEntry, tn, i, MUIV_NListtree_GetEntry_Flag_SameLevel, 0)))
  140.             {
  141.                struct ABEntry *ab2 = tn2->tn_User;
  142.                if ((retcode = WR_ResolveName(winnum, ab2->Alias, adrstr, nolists))) return retcode;
  143.             }
  144.             else break;
  145.          break;
  146.    }
  147.    return 0;
  148. }
  149.  
  150.  
  151. ///
  152. /// WR_ExpandAddresses
  153. //  Expands aliases and names in a recipient field to valid e-mail addresses
  154. char *WR_ExpandAddresses(int winnum, char *src, BOOL quiet, BOOL single)
  155. {
  156.    char *source, *buffer = malloc(strlen(src)+1), *next, *adr = AllocStrBuf(SIZE_DEFAULT);
  157.    int err;
  158.  
  159.    strcpy(source = buffer, src);
  160.    while (source)
  161.    {
  162.       if (!*source) break;
  163.       if ((next = MyStrChr(source, ','))) *next++ = 0;
  164.       if ((err = WR_ResolveName(winnum, Trim(source), &adr, single)))
  165.       {
  166.          if (err == 2 && !quiet) ER_NewError(GetStr(MSG_ER_AliasNotFound), FailedAlias, NULL);
  167.          if (err == 3 && !quiet) ER_NewError(GetStr(MSG_ER_AmbiguousAlias), FailedAlias, NULL);
  168.          if (err == 4 && !quiet) ER_NewError(GetStr(MSG_ER_InvalidAlias), FailedAlias, NULL);
  169.          FreeStrBuf(adr); adr = NULL;
  170.          break;
  171.       }
  172.       if (single) break;
  173.       source = next;
  174.    }
  175.    free(buffer);
  176.    return adr;
  177. }
  178.  
  179.  
  180. ///
  181. /// WR_VerifyAutoFunc
  182. //  Checks recipient field (user pressed return key)
  183. void SAVEDS ASM WR_VerifyAutoFunc(REG(a1,int *arg))
  184. {
  185.    APTR str = (APTR)arg[0], next = str;
  186.    char *value, *adr;
  187.    get(str, MUIA_String_Contents, &value);
  188.    if ((adr = WR_ExpandAddresses(arg[1], value, TRUE, arg[2])))
  189.    {
  190.       setstring(str, adr);
  191.       FreeStrBuf(adr);
  192.       get(str, MUIA_UserData, &next);
  193.    }
  194.    else DisplayBeep(0);
  195.    if (next) set(_win(next), MUIA_Window_ActiveObject, next);
  196. }
  197. MakeHook(WR_VerifyAutoHook, WR_VerifyAutoFunc);
  198.  
  199.  
  200. ///
  201. /// WR_VerifyManualFunc
  202. //  Checks and expands recipient field (user clicked gadget)
  203. void SAVEDS ASM WR_VerifyManualFunc(REG(a1,int *arg))
  204. {
  205.    APTR object = (APTR)arg[0];
  206.    char *value, *adr;
  207.    get(object, MUIA_String_Contents, &value);
  208.    if ((adr = WR_ExpandAddresses(arg[1], value, FALSE, arg[2])))
  209.    {
  210.       setstring(object, adr);
  211.       FreeStrBuf(adr);
  212.    }
  213. }
  214. MakeHook(WR_VerifyManualHook, WR_VerifyManualFunc);
  215. ///
  216.  
  217.  
  218. /*** Attachments list ***/
  219. /// WR_GetFileEntry
  220. //  Fills form with data from selected list entry
  221. void SAVEDS ASM WR_GetFileEntry(REG(a1,int *arg))
  222. {
  223.    int winnum = *arg;
  224.    struct Attach *attach = NULL;
  225.    struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  226.  
  227.    DoMethod(gui->LV_ATTACH, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &attach);
  228.    DoMethod(G->App, MUIM_MultiSet, MUIA_Disabled, attach ? FALSE : TRUE, gui->RA_ENCODING, gui->ST_CTYPE, gui->ST_DESC, gui->BT_DEL, gui->BT_DISPLAY, NULL);
  229.    if (attach)
  230.    {
  231.       nnset(gui->RA_ENCODING, MUIA_Radio_Active, attach->IsMIME ? 0 : 1);
  232.       nnset(gui->ST_CTYPE, MUIA_String_Contents, attach->ContentType);
  233.       nnset(gui->ST_DESC, MUIA_String_Contents, attach->Description);
  234.    }
  235. }
  236. MakeHook(WR_GetFileEntryHook, WR_GetFileEntry);
  237.  
  238.  
  239. ///
  240. /// WR_PutFileEntry
  241. //  Fills form data into selected list entry
  242. void SAVEDS ASM WR_PutFileEntry(REG(a1,int *arg))
  243. {
  244.    int winnum = *arg;
  245.    struct Attach *attach = NULL;
  246.    struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  247.    int ismime;
  248.  
  249.    DoMethod(gui->LV_ATTACH, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &attach);
  250.    if (attach)
  251.    {
  252.       get(gui->RA_ENCODING, MUIA_Radio_Active, &ismime);
  253.       attach->IsMIME = ismime == 0;
  254.       GetMUIString(attach->ContentType, gui->ST_CTYPE);
  255.       GetMUIString(attach->Description, gui->ST_DESC);
  256.       DoMethod(gui->LV_ATTACH, MUIM_List_Redraw, MUIV_List_Redraw_Active);
  257.    }
  258. }
  259. MakeHook(WR_PutFileEntryHook, WR_PutFileEntry);
  260.  
  261.  
  262. ///
  263. /// WR_AddFileToList
  264. //  Adds a file to the attachment list, gets its size and type
  265. BOOL WR_AddFileToList(int winnum, char *filename, char *name, BOOL istemp)
  266. {
  267.    static struct Attach attach;
  268.    struct FileInfoBlock *fib;
  269.    struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  270.    char *ctype;
  271.    int encoding;
  272.    BPTR lock;
  273.  
  274.    if (!filename) return FALSE;
  275.    clear(&attach, sizeof(struct Attach));
  276.    if (!(lock = Lock(filename, ACCESS_READ))) return FALSE;
  277.    fib = AllocDosObject(DOS_FIB, NULL);
  278.    Examine(lock, fib);
  279.    attach.Size = fib->fib_Size;
  280.    stccpy(attach.Description, fib->fib_Comment, SIZE_DEFAULT);
  281.    FreeDosObject(DOS_FIB, fib);
  282.    UnLock(lock);
  283.    ctype = IdentifyFile(filename);
  284.    if (*ctype)
  285.    {  
  286.       strcpy(attach.FilePath, filename); 
  287.       strcpy(attach.Name, name ? name : (char *)FilePart(filename));
  288.       get(gui->RA_ENCODING, MUIA_Radio_Active, &encoding);
  289.       attach.IsMIME = encoding == 0;
  290.       attach.IsTemp = istemp;
  291.       strcpy(attach.ContentType, ctype);
  292.       nnset(gui->ST_CTYPE, MUIA_String_Contents, attach.ContentType);
  293.       nnset(gui->ST_DESC, MUIA_String_Contents, attach.Description);
  294.       DoMethod(gui->LV_ATTACH, MUIM_List_InsertSingle, &attach, MUIV_List_Insert_Bottom);
  295.       set(gui->LV_ATTACH, MUIA_List_Active, MUIV_List_Active_Bottom);
  296.       return TRUE;
  297.    }
  298.    return FALSE;
  299. }  
  300. ///
  301.  
  302.  
  303. /*** Compose Message ***/
  304. /// GetDateTime
  305. //  Formats current date and time for Date header field
  306. LOCAL char *GetDateTime(void)
  307. {
  308.    static char dt[SIZE_DEFAULT];
  309.    struct ClockData cd;
  310.    char *tz;
  311.  
  312.    Amiga2Date(GetDateStamp(), &cd);
  313.    sprintf(dt, "%s, %02ld %s %ld %02ld:%02ld:%02ld", wdays[cd.wday], cd.mday, months[cd.month-1], cd.year, cd.hour, cd.min, cd.sec);
  314.    if ((tz = GetTZ())) { strcat(dt, " "); strcat(dt, tz); }
  315.    return dt;  
  316. }
  317.  
  318.  
  319. ///
  320. /// NewID
  321. //  Creates a unique id, used for Message-ID header field
  322. LOCAL char *NewID(BOOL is_msgid)
  323. {
  324.    static char idbuf[SIZE_MSGID];
  325.    static int ctr = 0;
  326.    struct DateStamp ds;
  327.  
  328.    DateStamp(&ds);
  329.    if (is_msgid) sprintf(idbuf, "yam%ld.%ld.%ld@%s", ds.ds_Days, ds.ds_Tick, FindTask(NULL), C->SMTP_Server);
  330.    else          sprintf(idbuf, "%ld.%ld", FindTask(NULL), ++ctr);
  331.    return idbuf;
  332. }
  333.  
  334.  
  335. ///
  336. /// WhichEncodingForFile
  337. //  Determines best MIME encoding mode for a file
  338. LOCAL int WhichEncodingForFile(char *fname, char *ctype)
  339. {
  340.    int c, linesize=0, total=0, unsafechars=0, binarychars=0, longlines=0;
  341.    FILE *fh = fopen(fname, "r");
  342.  
  343.    if (!fh) return ENC_B64;
  344.    while ((c = fgetc(fh)) != -1)
  345.    {
  346.       if (c > 127) ++unsafechars;
  347.       if (c < 32 && c != '\t' && c != '\n' && c != '\r') ++binarychars;
  348.       ++total;
  349.       if (c == '\n') 
  350.       {
  351.          if (linesize > 79) ++longlines;
  352.          linesize = 0;
  353.       } else ++linesize;
  354.       if (total > 4000 && (longlines || unsafechars || binarychars)) break;
  355.    }
  356.    fclose(fh);
  357.    if (longlines || unsafechars || binarychars)
  358.    {
  359.       if (!strnicmp(ctype, "image/", 6) ||
  360.           !strnicmp(ctype, "audio/", 6) ||
  361.           !strnicmp(ctype, "application/octet-stream", 24) ||
  362.           !strnicmp(ctype, "video/", 6))
  363.          return ENC_B64;
  364.       if (!strnicmp(ctype, "message/", 8)) return (longlines) ? ENC_BIN : ENC_8BIT;
  365.       if (!unsafechars && !binarychars) return C->Allow8bit ? ENC_BIN : ENC_QP;
  366.       if (C->Allow8bit && !binarychars) return ENC_8BIT;
  367.       return (total/++unsafechars < 16) ? ENC_B64 : ENC_QP;
  368.    }
  369.    return ENC_NONE;
  370. }
  371.  
  372.  
  373. ///
  374. /// NewPart
  375. //  Initializes a new message part
  376. struct WritePart *NewPart(int winnum)
  377. {
  378.    struct WritePart *p;
  379.    p = (struct WritePart *)calloc(1,sizeof(struct WritePart));
  380.    p->ContentType = "text/plain";
  381.    p->EncType = ENC_NONE;
  382.    p->Filename = G->WR_Filename[winnum];
  383. //   p->Name = NULL; // redundant due to calloc() -msbethke
  384.    return p;
  385. }
  386.  
  387.  
  388. ///
  389. /// BuildPartsList
  390. //  Builds message parts from attachment list
  391. LOCAL struct WritePart *BuildPartsList(int winnum)
  392. {
  393.    int i;
  394.    struct Attach *att;
  395.    struct WritePart *first, *p, *np;
  396.  
  397.    first = p = NewPart(winnum); p->IsTemp = TRUE;
  398.    p->EncType = WhichEncodingForFile(p->Filename, p->ContentType);
  399.    for (i = 0; ; i++)
  400.    {
  401.       DoMethod(G->WR[winnum]->GUI.LV_ATTACH, MUIM_List_GetEntry, i, &att);
  402.       if (!att) break;
  403.       p->Next = np = NewPart(winnum); p = np;
  404.       p->ContentType = att->ContentType;
  405.       p->Filename    = att->FilePath;
  406.       p->Description = att->Description;     
  407.       p->Name        = att->Name;
  408.       p->IsTemp      = att->IsTemp;
  409.       if (att->IsMIME) p->EncType = WhichEncodingForFile(p->Filename, p->ContentType);
  410.       else p->EncType = ENC_UUE;
  411.    }
  412.    return first;
  413. }
  414.  
  415. ///
  416. /// FreePartsList
  417. //  Clears message parts and deletes temporary files
  418. void FreePartsList(struct WritePart *p)
  419. {
  420.    struct WritePart *np;
  421.    for (; p; p = np)
  422.    {
  423.       np = p->Next;
  424.       if (p->IsTemp) DeleteFile(p->Filename);
  425.       free(p);
  426.    }
  427. }
  428.  
  429. ///
  430. /// WR_CharOut
  431. //  Outputs a single byte of a message header
  432. LOCAL int WR_CharOut(char c)
  433. {
  434.    if (G->TTout) if (G->TTout->Header) return (int)G->TTout->Table[(UBYTE)c];
  435.    return (int)c;
  436. }
  437.  
  438. ///
  439. /// firstbad
  440. //  Returns a pointer to the first non-ascii or control character in a string
  441. LOCAL char *firstbad(char *s)
  442. {
  443.    unsigned char *dum;
  444.    for (dum = (unsigned char *)s; *dum; ++dum)
  445.       if (!isascii(WR_CharOut(*dum)) || iscntrl(WR_CharOut(*dum))) return (char *)dum;
  446.    return NULL;
  447. }
  448.  
  449. ///
  450. /// PutQP
  451. //  Outputs a base64 encoded, single byte of a message header
  452. LOCAL void PutQP(unsigned char c, FILE *fh)
  453. {
  454.    static char basis_hex[] = "0123456789ABCDEF";
  455.    fputc('=', fh);
  456.    fputc(basis_hex[c>>4], fh);
  457.    fputc(basis_hex[c&0xF], fh);
  458. }
  459.  
  460. ///
  461. /// HeaderFputs
  462. //  Outputs the value of a header line (optional QP encoding and charset translation)
  463. LOCAL void HeaderFputs(char *s, FILE *fh)
  464. {
  465.    char *firstnonascii, *wordstart;
  466.  
  467.    if (!s) return;
  468.    while ((firstnonascii = firstbad(s)))
  469.    {
  470.       for (wordstart = firstnonascii; wordstart >= s; wordstart--) if (ISpace(*wordstart)) break;
  471.       while (s <= wordstart) { fputc(WR_CharOut(*s), fh); ++s; }
  472.       fprintf(fh, "=?%s?Q?", G->TTout ? G->TTout->DestCharset : C->LocalCharset);
  473.       for (; *s && !ISpace(*s); ++s)
  474.       {
  475.          char c = (char)WR_CharOut(*s);
  476.          if (c > ' ') fputc(c, fh); else PutQP((unsigned char)c, fh);
  477.          }
  478.       fputs("?=", fh);
  479.    }
  480.    while (*s) { fputc(WR_CharOut(*s), fh); ++s; }
  481. }
  482.  
  483. ///
  484. /// EmitHeader
  485. //  Outputs a complete header line
  486. void EmitHeader(FILE *fh, char *hdr, char *body)
  487. {
  488.    fprintf(fh, "%s: ", hdr);
  489.    HeaderFputs(body, fh);
  490.    fputc('\n', fh);
  491. }
  492.  
  493. ///
  494. /// EmitRcptField
  495. //  Outputs the value of a recipient header line, one entry per line
  496. LOCAL void EmitRcptField(FILE *fh, char *body)
  497. {
  498.    char *part, *next, *bodycpy = malloc(strlen(body)+1);
  499.  
  500.    strcpy(part = bodycpy, body);
  501.    while (part)
  502.    {
  503.       if (!*part) break;
  504.       if ((next = MyStrChr(part, ','))) *next++ = 0;
  505.       HeaderFputs(Trim(part), fh);
  506.       if ((part = next)) fputs(",\n\t", fh);
  507.    }
  508.    free(bodycpy);
  509.  
  510. ///
  511. /// EmitRcptHeader
  512. //  Outputs a complete recipient header line
  513. LOCAL void EmitRcptHeader(FILE *fh, char *hdr, char *body)
  514. {
  515.    fprintf(fh, "%s: ", hdr);
  516.    EmitRcptField(fh, body ? body : "");
  517.    fputc('\n', fh);
  518.  
  519. ///
  520. /// FPutsQuoting
  521. //  Handles quotes and slashes
  522. LOCAL void FPutsQuoting(char *s, FILE *fh)
  523. {
  524.    char *end = s + strlen(s) - 1;
  525.    while (ISpace(*end) && end > s) --end;
  526.    if (*s == '\"') 
  527.    {
  528.       fputc(*s, fh);
  529.       while (*++s) 
  530.       {
  531.          if (*s == '\"') break;
  532.          if (*s == '\\') { fputc(*s, fh); ++s; if (!*s) break; }
  533.          fputc(*s, fh);
  534.       }
  535.       fputc('\"', fh);
  536.    }
  537.    else 
  538.    {
  539.       fputc('\"', fh); fputc(*s, fh);
  540.       while (*++s) 
  541.       {
  542.          if (*s == '\"' || *s == '\\') fputc('\\', fh);
  543.          fputc(*s, fh);
  544.       }
  545.       fputc('\"', fh);
  546.    }
  547. }
  548.  
  549. ///
  550. /// WriteCtypeNicely
  551. //  Outputs content type
  552. LOCAL void WriteCtypeNicely(FILE *fh, char *ct)
  553. {
  554.    char *semi, *slash, *eq, *s;
  555.  
  556.    for (s = ct; *s; ++s) if (*s == '\n') *s = ' ';
  557.    if ((semi = (char *)index(ct, ';'))) *semi = '\0';
  558.    slash = (char *)index(ct, '/');
  559.    fputs(ct, fh);
  560.    if (!slash) fputs("/unknown", fh);
  561.    while (semi) 
  562.    {
  563.       ct = semi + 1;
  564.       *semi = ';';
  565.       if ((semi = (char *) index(ct, ';'))) *semi = '\0';
  566.       if ((eq = (char *) index(ct, '='))) *eq = '\0';
  567.       fputs(";\n\t", fh);
  568.       while (ISpace(*ct)) ++ct;
  569.       fputs(ct, fh);
  570.       if (eq) 
  571.       {
  572.          s = eq;
  573.          fputc('=', fh);
  574.          ++s;
  575.          while (ISpace(*s)) ++s;
  576.          FPutsQuoting(s, fh);
  577.          *eq = '=';
  578.       }
  579.    }
  580. }
  581. ///
  582. /// WriteContentTypeAndEncoding
  583. //  Outputs content type header including parameters
  584. LOCAL void WriteContentTypeAndEncoding(FILE *fh, struct WritePart *part)
  585. {
  586.    char *p;
  587.    fputs("Content-Type: ", fh);
  588.    WriteCtypeNicely(fh, part->ContentType);
  589.    if (!strncmp(part->ContentType, "text/", 5) && (part->EncType != ENC_NONE || part->TTable))
  590.       fprintf(fh, "; charset=%s", part->TTable ? part->TTable->DestCharset : C->LocalCharset);
  591.    if ((p = part->Name)) if (*p) 
  592.    {
  593.       fputs("; name=\"", fh);
  594.       HeaderFputs(p, fh);
  595.       fputs("\"\nContent-Disposition: attachment; filename=\"", fh);
  596.       HeaderFputs(p, fh);
  597.       fputc('\"', fh);
  598.    }
  599.    fputc('\n', fh);
  600.    if (part->EncType != ENC_NONE)
  601.    {
  602.       fputs("Content-Transfer-Encoding: ", fh);
  603.       switch (part->EncType)
  604.       {
  605.          case ENC_B64:  fputs("base64\n", fh); break;
  606.          case ENC_QP:   fputs("quoted-printable\n", fh); break;
  607.          case ENC_UUE:  fputs("x-uue\n", fh); break;
  608.          case ENC_8BIT: fputs("8bit\n", fh); break;
  609.          case ENC_BIN:  fputs("binary\n", fh); break;
  610.       }
  611.    }
  612.    if ((p = part->Description)) if (*p) EmitHeader(fh, "Content-Description", p);
  613. }
  614.  
  615. ///
  616. /// WR_WriteUIItem
  617. //  Outputs a single parameter of the X-SenderInfo header
  618. LOCAL void WR_WriteUIItem(FILE *fh, int *len, char *parameter, char *value)
  619. {
  620.    int l = 6+strlen(parameter)+strlen(value);
  621.    *len += l;
  622.    fputc(';', fh); if (*len > 80) { fputs("\n  ", fh); *len = l; }
  623.    fprintf(fh, " %s=\"", parameter);
  624.    HeaderFputs(value, fh);
  625.    fputc('\"', fh);
  626. }
  627.  
  628. ///
  629. /// WR_WriteUserInfo
  630. //  Outputs X-SenderInfo header line
  631. LOCAL void WR_WriteUserInfo(FILE *fh)
  632. {
  633.    int len = 15, hits = 0;
  634.    struct ABEntry *ab = NULL;
  635.    struct MUI_NListtree_TreeNode *tn;
  636.  
  637.    if (AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, C->EmailAddress, ASM_ADDRESS|ASM_USER, &hits, &tn))
  638.    {
  639.       ab = tn->tn_User;
  640.       if (ab->Type != AET_USER) ab = NULL;
  641.       else if (!*ab->Homepage && !*ab->Phone && !*ab->Street && !*ab->City && !*ab->Country && !ab->BirthDay) ab = NULL;
  642.    }
  643.    if (!ab && !*C->MyPictureURL) return;
  644.    fputs("X-SenderInfo: 1", fh);
  645.    if (*C->MyPictureURL) WR_WriteUIItem(fh, &len, "picture", C->MyPictureURL);
  646.    if (ab)
  647.    {
  648.       if (*ab->Homepage) WR_WriteUIItem(fh, &len, "homepage", ab->Homepage);
  649.       if (*ab->Street)   WR_WriteUIItem(fh, &len, "street", ab->Street);
  650.       if (*ab->City)     WR_WriteUIItem(fh, &len, "city", ab->City);
  651.       if (*ab->Country)  WR_WriteUIItem(fh, &len, "country", ab->Country);
  652.       if (*ab->Phone)    WR_WriteUIItem(fh, &len, "phone", ab->Phone);
  653.       if (ab->BirthDay)  fprintf(fh, "; dob=%ld", ab->BirthDay);
  654.    }
  655.    fputc('\n', fh);
  656. }
  657. ///
  658. /// EncodePart
  659. //  Encodes a message part
  660. LOCAL void EncodePart(FILE *ofh, struct WritePart *part)
  661. {
  662.    FILE *ifh;
  663.  
  664.    if ((ifh = fopen(part->Filename, "r")))
  665.    {
  666.       int size;
  667.       switch (part->EncType) 
  668.       {
  669.          case ENC_B64: to64(ifh, ofh, DoesNeedPortableNewlines(part->ContentType));
  670.                        break;
  671.          case ENC_QP:  toqp(ifh, ofh);
  672.                        break;
  673.          case ENC_UUE: size = FileSize(part->Filename);
  674.                        fprintf(ofh, "begin 644 %s\n", *part->Name ? part->Name : (char *)FilePart(part->Filename));
  675.                        touue(ifh, ofh);
  676.                        fprintf(ofh, "end\nsize %ld\n", size);
  677.                        break;
  678.          default:      CopyFile(NULL, ofh, NULL, ifh);
  679.       }
  680.       fclose(ifh);
  681.    }
  682. }
  683.  
  684. ///
  685. /// WR_CreateHashTable
  686. //  Creates an index table for a database file
  687. LOCAL BOOL WR_CreateHashTable(char *source, char *hashfile, char *sep)
  688. {
  689.    char buffer[SIZE_LARGE];
  690.    long fpos, l = strlen(sep);
  691.    FILE *in, *out;
  692.    BOOL success = FALSE;
  693.  
  694.    if ((in = fopen(source, "r")))
  695.    {
  696.       if ((out = fopen(hashfile, "w")))
  697.       {
  698.          fpos = 0; fwrite(&fpos, sizeof(long), 1, out);
  699.          while (fgets(buffer, SIZE_LARGE, in))
  700.             if (!strncmp(buffer, sep, l)) { fpos = ftell(in); fwrite(&fpos, sizeof(long), 1, out); }
  701.          success = TRUE;
  702.          fclose(out);
  703.       }
  704.       fclose(in);
  705.    }
  706.    return success;
  707. }
  708.  
  709. ///
  710. /// WR_AddTagline
  711. //  Randomly selects a tagline and writes it to the message file
  712. LOCAL void WR_AddTagline(FILE *fh_mail)
  713. {
  714.    FILE *fh_tag, *fh_hash;
  715.    char buf[SIZE_LARGE], hashfile[SIZE_PATHFILE];
  716.    long fpos, hsize;
  717.  
  718.    if (*C->TagsFile) 
  719.    {
  720.       sprintf(hashfile, "%s.hsh", C->TagsFile);
  721.       if (getft(C->TagsFile) > getft(hashfile)) WR_CreateHashTable(C->TagsFile, hashfile, C->TagsSeparator);
  722.       if ((fh_tag = fopen(C->TagsFile, "r")))
  723.       {
  724.          if ((fh_hash = fopen(hashfile, "r")))
  725.          {
  726.             fseek(fh_hash, 0, SEEK_END); hsize = ftell(fh_hash);
  727.             if ((hsize = hsize/sizeof(long)) > 1)
  728.             {
  729.                fpos = (((long)rand())%hsize)*sizeof(long);
  730.                fseek(fh_hash, fpos, SEEK_SET); fread(&fpos, sizeof(long), 1, fh_hash);
  731.                fseek(fh_tag, fpos, SEEK_SET);
  732.                if (GetLine(fh_tag, buf, SIZE_LARGE)) fputs(buf, fh_mail);
  733.                while (GetLine(fh_tag, buf, SIZE_LARGE))
  734.                   if (!strncmp(buf, C->TagsSeparator, strlen(C->TagsSeparator))) break;
  735.                   else fprintf(fh_mail, "\n%s", buf);
  736.             }
  737.             fclose(fh_tag);
  738.          }
  739.          else ER_NewError(GetStr(MSG_ER_CantOpenFile), hashfile, NULL);
  740.       }
  741.       else ER_NewError(GetStr(MSG_ER_CantOpenFile), C->TagsFile, NULL);
  742.    }
  743. }
  744.  
  745. ///
  746. /// WR_WriteSignature
  747. //  Writes signature to the message file
  748. LOCAL void WR_WriteSignature(FILE *out, int signat)
  749. {
  750.    FILE *in;
  751.    int ch;
  752.    if ((in = fopen(CreateFilename(SigNames[signat]), "r")))
  753.    {
  754.       fputs("-- \n", out);
  755.       while ((ch = fgetc(in)) != EOF)
  756.       {
  757.          if (ch == '%')
  758.          {
  759.             ch = fgetc(in);
  760.             if (ch == 't') { WR_AddTagline(out); continue; }
  761.             if (ch == 'e') { CopyFile(NULL, out, "ENV:SIGNATURE", NULL); continue; }
  762.             ungetc(ch, in); ch = '%';
  763.          }
  764.          fputc(ch, out);
  765.       }
  766.       fclose(in);
  767.    }
  768. }
  769.  
  770. ///
  771. /// WR_AddSignature
  772. //  Adds a signature to the end of the file
  773. void WR_AddSignature(char *mailfile, int signat)
  774. {
  775.    FILE *fh_mail;
  776.    BOOL addline = FALSE;
  777.  
  778.    if (signat == -1) 
  779.    {
  780.       signat = C->UseSignature ? 1 : 0;
  781.       if ((fh_mail = fopen(mailfile, "r")))
  782.       {
  783.          fseek(fh_mail, -1, SEEK_END);
  784.          addline = fgetc(fh_mail) != '\n';
  785.          fclose(fh_mail);
  786.       }
  787.    }
  788.    if ((fh_mail = fopen(mailfile, "a")))
  789.    {
  790.       if (addline) fputc('\n', fh_mail);
  791.       if (signat) WR_WriteSignature(fh_mail, signat-1);
  792.       fclose(fh_mail);
  793.    }
  794. }
  795.  
  796. ///
  797. /// WR_Anonymize
  798. //  Inserts recipient header field for remailer service
  799. LOCAL void WR_Anonymize(FILE *fh, char *body)
  800. {
  801.    char *ptr;
  802.  
  803.    for (ptr = C->RMCommands; *ptr; ptr++)
  804.    {
  805.       if (*ptr == '\\') if (*(ptr+1) == 'n') { ptr++; fputs("\n", fh); continue; }
  806.       if (*ptr == '%') if (*(ptr+1) == 's') { ptr++; EmitRcptField(fh, body); continue; }
  807.       fputc(*ptr, fh);
  808.    }
  809.    fputs("\n", fh);
  810. }
  811.  
  812. ///
  813. /// WR_GetPGPId
  814. //  Gets PGP key id for a person
  815. LOCAL char *WR_GetPGPId(struct Person *pe)
  816. {
  817.    int hits;
  818.    char *pgpid = NULL;
  819.    struct MUI_NListtree_TreeNode *tn;
  820.    if (!AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, pe->RealName, ASM_REALNAME|ASM_USER, &hits, &tn))
  821.         AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, pe->Address, ASM_ADDRESS|ASM_USER, &hits, &tn);
  822.    if (hits && tn && tn->tn_User)
  823.         if (((struct ABEntry *)(tn->tn_User))->PGPId[0])
  824.             pgpid = ((struct ABEntry *)(tn->tn_User))->PGPId;
  825.    return pgpid;
  826. }
  827. ///
  828. /// WR_GetPGPIds
  829. //  Collects PGP key ids for all persons in a recipient field
  830. LOCAL char *WR_GetPGPIds(char *source, char *ids)
  831. {
  832.    struct Person pe;
  833.    char *next, *pid;
  834.  
  835.    for (; source; source = next)
  836.    {
  837.       if (!*source) break;
  838.       if ((next = MyStrChr(source, ','))) *next++ = 0;
  839.       ExtractAddress(source, &pe);
  840.       if (!(pid = WR_GetPGPId(&pe)))
  841.       {
  842.          pid = pe.RealName[0] ? pe.RealName : pe.Address;
  843.          ER_NewError(GetStr(MSG_ER_ErrorNoPGPId), source, pid);
  844.       }
  845.       ids = StrBufCat(ids, (G->PGPVersion == 5) ? "-r \"" : "\"");
  846.       ids = StrBufCat(ids, pid);
  847.       ids = StrBufCat(ids, "\" ");
  848.    }
  849.    return ids;
  850. }
  851. ///
  852.  
  853. /// WR_Bounce
  854. //  Bounce message: inserts resent-headers while copying the message
  855. LOCAL BOOL WR_Bounce(FILE *fh, struct Compose *comp)
  856. {
  857.    FILE *oldfh;
  858.    if ((oldfh = fopen(GetMailFile(NULL, NULL, comp->OrigMail), "r")))
  859.    {
  860.       BOOL infield = FALSE, inbody = FALSE;
  861.       char buf[SIZE_LINE];
  862.       while (fgets(buf, SIZE_LINE, oldfh))
  863.       {
  864.          if (*buf == '\n' && !inbody)
  865.          {
  866.             inbody = TRUE;
  867.             EmitRcptHeader(fh, "To", comp->MailTo);
  868.             EmitHeader(fh, "Resent-From", BuildAddrName(C->EmailAddress, C->RealName));
  869.             EmitHeader(fh, "Resent-Date", GetDateTime());
  870.          }
  871.          if (!ISpace(*buf) && !inbody) infield = !strnicmp(buf, "to:", 3);
  872.          if (!infield || inbody) fputs(buf, fh);
  873.       }
  874.       fclose(oldfh);
  875.       return TRUE;
  876.    }
  877.    return FALSE;
  878. }
  879.  
  880. ///
  881. /// WR_SaveDec
  882. //  Creates decrypted copy of a PGP encrypted message
  883. LOCAL BOOL WR_SaveDec(FILE *fh, struct Compose *comp)
  884. {
  885.    FILE *oldfh;
  886.    if ((oldfh = fopen(GetMailFile(NULL, NULL, comp->OrigMail), "r")))
  887.    {
  888.       BOOL infield = FALSE;
  889.       char buf[SIZE_LINE];
  890.       while (fgets(buf, SIZE_LINE, oldfh))
  891.       {
  892.          if (*buf == '\n') { fprintf(fh, "X-YAM-Decrypted: PGP; %s\n", GetDateTime()); break; }
  893.          if (!ISpace(*buf)) infield = !strnicmp(buf, "content-type:", 13)
  894.                                    || !strnicmp(buf, "content-transfer-encoding", 25)
  895.                                    || !strnicmp(buf, "mime-version:", 13);
  896.          if (!infield) fputs(buf, fh);
  897.       }
  898.       fclose(oldfh);
  899.       return TRUE;
  900.    }
  901.    return FALSE;
  902. }
  903.  
  904. ///
  905. /// WR_EmitExtHeader
  906. //  Outputs special X-YAM-Header lines to remember user-defined headers
  907. LOCAL void WR_EmitExtHeader(FILE *fh, struct Compose *comp)
  908. {
  909.    if (*comp->ExtHeader)
  910.    {
  911.       char *p, ch = '\n';
  912.       for (p = comp->ExtHeader; *p; ++p)
  913.       {
  914.          if (ch == '\n') fputs("X-YAM-Header-", fh);
  915.          if (*p != '\\') ch = *p;
  916.          else if (*++p == '\\') ch = '\\'; else if (*p == 'n') ch = '\n';
  917.          fputc(ch, fh);
  918.       }
  919.       if (ch != '\n') fputc('\n', fh);
  920.    }
  921. }
  922.  
  923. ///
  924. /// WR_ComposeReport
  925. //  Assembles the parts of a message disposition notification
  926. LOCAL const char *MIMEwarn = "Warning: This is a message in MIME format. Your mail reader does not\n"
  927.                              "support MIME. Some parts of this message will be readable as plain text.\n"
  928.                              "To see the rest, you will need to upgrade your mail reader. Following are\n"
  929.                              "some URLs where you can find MIME-capable mail programs for common platforms:\n\n"
  930.                              "  Amiga............: YAM          http://www.yam.ch/\n"
  931.                              "  Unix.............: Metamail     ftp://ftp.bellcore.com/nsb/\n"
  932.                              "  Windows/Macintosh: Eudora       http://www.qualcomm.com/\n\n"
  933.                              "General info about MIME can be found at:\n\n"
  934.                              "http://www.cis.ohio-state.edu/hypertext/faq/usenet/mail/mime-faq/top.html\n\n";
  935. LOCAL const char *PGPwarn  = "The following body part contains a PGP encrypted message. Either your\n"
  936.                              "mail reader doesn't support MIME/PGP as specified in RFC 2015, or\n"
  937.                              "the message was encrypted for someone else. To read the encrypted\n"
  938.                              "message, run the next body part through Pretty Good Privacy.\n\n";
  939. LOCAL void WR_ComposeReport(FILE *fh, struct Compose *comp, char *boundary)
  940. {
  941.    struct WritePart *p;
  942.    fprintf(fh, "Content-type: multipart/report; report-type=disposition-notification; boundary=\"%s\"\n\n", boundary);
  943.    for (p = comp->FirstPart; p; p = p->Next)
  944.    {
  945.       fprintf(fh, "\n--%s\n", boundary);
  946.       WriteContentTypeAndEncoding(fh, p);
  947.       fputs("\n", fh);
  948.       EncodePart(fh, p);
  949.    }
  950.    fprintf(fh, "\n--%s--\n\n", boundary);
  951. }
  952.  
  953. LOCAL void SetDefaultSecurity(struct Compose *comp)
  954. {
  955. STRPTR CheckThese[3],buf;
  956. int i, Security=0;
  957. BOOL FirstAddr=TRUE;
  958.  
  959.     /* collect address pointers for easier iteration */
  960.     CheckThese[0] = comp->MailTo;
  961.     CheckThese[1] = comp->MailCC;
  962.     CheckThese[2] = comp->MailBCC;
  963.  
  964.     /* go through all addresses */
  965.     for(i=0; i<3; i++)
  966.     {
  967.         if(CheckThese[i] == NULL) continue;        // skip empty fields
  968.         // copy string as strtok() will modify it
  969.         if((buf = (STRPTR)strdup(CheckThese[i])))
  970.         {
  971.         int hits = 0, currsec;
  972.         STRPTR in=buf,s,t;
  973.         struct MUI_NListtree_TreeNode *tn;
  974.  
  975.             // loop through comma-separated addresses in string
  976.             while((s = strtok_r((char **)&in,",")))
  977.             {
  978.                 while((t = strtok_r((char **)&s," ()<>")))
  979.                     if(strchr(t,'@')) break;
  980.  
  981.                 if(!t) continue; // can't find address for this entry - shouldn't happen
  982.  
  983.                 if(AB_SearchEntry(MUIV_NListtree_GetEntry_ListNode_Root, t, ASM_ADDRESS|ASM_USER|ASM_COMPLETE, &hits, &tn) && (NULL != tn->tn_User))
  984.                     currsec = ((struct ABEntry*)(tn->tn_User))->DefSecurity;    // get default from entry
  985.                 else
  986.                     currsec = 0;        // entry not in address book -> no security
  987.  
  988.                 if(currsec != Security)
  989.                 {
  990.                     if(FirstAddr)        // first address' setting is always used
  991.                     {
  992.                         FirstAddr = FALSE;
  993.                         Security = currsec;    // assume as default
  994.                     } else                        // conflict: two addresses have different defaults
  995.                     {
  996.                         Security = MUI_RequestA(G->App, NULL, 0, NULL, GetStr(MSG_WR_DefSecurityConflictGads),
  997.                                                         GetStr(MSG_WR_DefSecurityConflict),NULL);
  998.                         if(SEC_NONE == Security) Security = SEC_MAXDUMMY-1;    // correct 1..N numbering of requester buttons
  999.                         else Security--;
  1000.                         break;    // terminate recipient loop
  1001.                     }
  1002.                 }
  1003.             }
  1004.             free(buf);
  1005.         }
  1006.     }
  1007.     comp->Security = Security;
  1008. }
  1009.  
  1010. ///
  1011. /// WR_ComposePGP
  1012. //  Creates a signed and/or encrypted PGP/MIME message
  1013. LOCAL BOOL WR_ComposePGP(FILE *fh, struct Compose *comp, char *boundary)
  1014. {
  1015.    int sec = comp->Security;
  1016.    BOOL success = FALSE;
  1017.    struct WritePart pgppart, *firstpart = comp->FirstPart;
  1018.    char *ids = AllocStrBuf(SIZE_DEFAULT), pgpfile[SIZE_PATHFILE], options[SIZE_LARGE];
  1019.    struct TempFile *tf, *tf2;
  1020.  
  1021.    pgppart.Filename = pgpfile; *pgpfile = 0;
  1022.    pgppart.EncType = ENC_NONE;
  1023.    if((sec == SEC_ENCRYPT) || (sec == SEC_BOTH))
  1024.    {
  1025.       if (comp->MailTo) ids = WR_GetPGPIds(comp->MailTo, ids);
  1026.       if (comp->MailCC) ids = WR_GetPGPIds(comp->MailCC, ids);
  1027.       if (comp->MailBCC) ids = WR_GetPGPIds(comp->MailBCC, ids);
  1028.       if (C->EncryptToSelf && *C->MyPGPID)
  1029.       {
  1030.          if (G->PGPVersion == 5) ids = StrBufCat(ids, "-r ");
  1031.          ids = StrBufCat(ids, C->MyPGPID);
  1032.       }
  1033.    }
  1034.    tf2 = OpenTempFile(NULL);
  1035.    if ((tf = OpenTempFile("w")))
  1036.    {
  1037.       WriteContentTypeAndEncoding(tf->FP, firstpart);
  1038.       fputc('\n', tf->FP);
  1039.       EncodePart(tf->FP, firstpart);
  1040.       fclose(tf->FP); tf->FP = NULL;
  1041.       ConvertCRLF(tf->Filename, tf2->Filename, TRUE);
  1042.       CloseTempFile(tf);
  1043.       sprintf(pgpfile, "%s.asc", tf2->Filename);
  1044.       if((sec == SEC_SIGN) || (sec == SEC_BOTH)) PGPGetPassPhrase();
  1045.       switch (sec)
  1046.       {
  1047.          case SEC_SIGN :
  1048.             fprintf(fh, "Content-type: multipart/signed; boundary=\"%s\"; micalc=pgp-md5; protocol=\"application/pgp-signature\"\n\n%s\n--%s\n", boundary, MIMEwarn, boundary);
  1049.             WriteContentTypeAndEncoding(fh, firstpart);
  1050.             fputc('\n', fh);
  1051.             EncodePart(fh, firstpart);
  1052.             fprintf(fh, "\n--%s\nContent-Type: application/pgp-signature\n\n", boundary);
  1053.             sprintf(options, (G->PGPVersion == 5) ? "-ab %s +batchmode=1 +force" : "-sab %s +bat +f", tf2->Filename);
  1054.             if (*C->MyPGPID) { strcat(options, " -u "); strcat(options, C->MyPGPID); }
  1055.             if (!PGPCommand((G->PGPVersion == 5) ? "pgps" : "pgp", options, 0)) success = TRUE;
  1056.             break;
  1057.          case SEC_ENCRYPT :
  1058.             fprintf(fh, "Content-type: multipart/encrypted; boundary=\"%s\"; protocol=\"application/pgp-encrypted\"\n\n%s\n--%s\n", boundary, MIMEwarn, boundary);
  1059.             fprintf(fh, "Content-Type: application/pgp-encrypted\n\nVersion: 1\n\n%s\n--%s\nContent-Type: application/octet-stream\n\n", PGPwarn, boundary);
  1060.             sprintf(options, (G->PGPVersion == 5) ? "-a %s %s +batchmode=1 +force" : "-ea %s %s +bat +f", tf2->Filename, ids);
  1061.             if (!PGPCommand((G->PGPVersion == 5) ? "pgpe" : "pgp", options, 0)) success = TRUE;
  1062.             break;
  1063.          case SEC_BOTH :
  1064.             fprintf(fh, "Content-type: multipart/encrypted; boundary=\"%s\"; protocol=\"application/pgp-encrypted\"\n\n%s\n--%s\n", boundary, MIMEwarn, boundary);
  1065.             fprintf(fh, "Content-Type: application/pgp-encrypted\n\nVersion: 1\n\n%s\n--%s\nContent-Type: application/octet-stream\n\n", PGPwarn, boundary);
  1066.             sprintf(options, (G->PGPVersion == 5) ? "-a %s %s +batchmode=1 +force -s" : "-sea %s %s +bat +f", tf2->Filename, ids);
  1067.             if (*C->MyPGPID) { strcat(options, " -u "); strcat(options, C->MyPGPID); }
  1068.             if (!PGPCommand((G->PGPVersion == 5) ? "pgpe" : "pgp", options, 0)) success = TRUE;
  1069.             break;
  1070.       }
  1071.       if (success) EncodePart(fh, &pgppart);
  1072.    }
  1073.    CloseTempFile(tf2);
  1074.    if (*pgpfile) remove(pgpfile);
  1075.    fprintf(fh, "\n--%s--\n\n", boundary);
  1076.    FreeStrBuf(ids);
  1077.    PGPClearPassPhrase(!success);
  1078.    return success;
  1079. }
  1080.  
  1081. ///
  1082. /// WR_ComposeMulti
  1083. //  Assembles a multipart message
  1084. LOCAL void WR_ComposeMulti(FILE *fh, struct Compose *comp, char *boundary)
  1085. {
  1086.    struct WritePart *p;
  1087.    fprintf(fh, "Content-type: multipart/mixed; boundary=\"%s\"\n\n", boundary);
  1088.    fputs(MIMEwarn, fh);
  1089.    for (p = comp->FirstPart; p; p = p->Next)
  1090.    {
  1091.       fprintf(fh, "\n--%s\n", boundary);
  1092.       WriteContentTypeAndEncoding(fh, p);
  1093.       if (comp->Security == SEC_SENDANON) WR_Anonymize(fh, comp->MailTo);
  1094.       fputs("\n", fh);
  1095.       EncodePart(fh, p);
  1096.    }
  1097.    fprintf(fh, "\n--%s--\n\n", boundary);
  1098. }
  1099.  
  1100. ///
  1101. /// WriteOutMessage
  1102. //  Outputs header and body of a new message
  1103. BOOL WriteOutMessage(struct Compose *comp)
  1104. {
  1105. BOOL success=FALSE;
  1106. struct TempFile *tf=NULL;
  1107. FILE *fh = comp->FH;
  1108. struct WritePart *firstpart = comp->FirstPart;
  1109. char boundary[SIZE_DEFAULT], options[SIZE_DEFAULT], *rcptto;
  1110.  
  1111.    if (comp->Mode == NEW_BOUNCE)
  1112.    {
  1113.       if (comp->DelSend) EmitHeader(fh, "X-YAM-Options", "delsent");
  1114.       return WR_Bounce(fh, comp);
  1115.    }
  1116.    if (comp->Mode == NEW_SAVEDEC) if (!WR_SaveDec(fh, comp)) return FALSE; else goto mimebody;
  1117.    if (!firstpart) return FALSE;
  1118.  
  1119.    // encrypted multipart message requested?
  1120.    if (firstpart->Next && comp->Security > SEC_NONE  && comp->Security <= SEC_BOTH)
  1121.    {
  1122.       struct Compose tcomp;
  1123.       FILE *tfh;
  1124.  
  1125.          if((tf = OpenTempFile(NULL)) && (tfh = fopen(tf->Filename,"w")))
  1126.          {
  1127.             memcpy(&tcomp,comp,sizeof(tcomp));   // clone struct Compose
  1128.             tcomp.FH = tfh;                      // set new filehandle
  1129.             tcomp.Security = SEC_NONE;           // temp msg gets attachments and no security
  1130.  
  1131.             // clear a few other fields to avoid redundancies
  1132.             tcomp.MailCC = tcomp.MailBCC = tcomp.ExtHeader = NULL;
  1133.             tcomp.Receipt = tcomp.Importance = 0;
  1134.             tcomp.DelSend = tcomp.UserInfo = FALSE;
  1135.  
  1136.             if(WriteOutMessage(&tcomp))    // recurse!
  1137.             {
  1138.                struct WritePart *tpart = comp->FirstPart; // save parts list so we're able to recover from a calloc() error
  1139.  
  1140.                // replace with single new part
  1141.                if((comp->FirstPart = (struct WritePart *)calloc(1,sizeof(struct WritePart))))
  1142.                {
  1143.                   comp->FirstPart->EncType = tpart->EncType;          // reuse encoding
  1144.                   FreePartsList(tpart);                               // free old parts list
  1145.                   comp->FirstPart->ContentType = "message/rfc822";    // the only part is an email message
  1146.                   comp->FirstPart->Filename = tf->Filename;           // set filename to tempfile
  1147.                   comp->Signature = 0;                                // only use sig in enclosed mail
  1148.                } else
  1149.                {
  1150.                   // no errormsg here - the window probably won't open anyway...
  1151.                   DisplayBeep(NULL);
  1152.                   comp->FirstPart = tpart;     // just restore old parts list
  1153.                   comp->Security = 0;          // switch off security
  1154.                   // we'll most likely get more errors further down :(
  1155.                }
  1156.          } else
  1157.          {
  1158.             ER_NewError(GetStr(MSG_ER_PGPMultipart),NULL,NULL);
  1159.             comp->Security = 0;
  1160.          }
  1161.          fclose(tfh);
  1162.          } else
  1163.          {
  1164.             ER_NewError(GetStr(MSG_ER_PGPMultipart),NULL,NULL);
  1165.             comp->Security = 0;
  1166.          }
  1167.    }
  1168.    *options = 0;
  1169.    if (comp->DelSend) strcat(options, ",delsent");
  1170.    if (comp->Security) sprintf(&options[strlen(options)], ",%s", SecCodes[comp->Security]);
  1171.    if (comp->Signature) sprintf(&options[strlen(options)], ",sigfile%ld", comp->Signature-1);
  1172.    if (*options) EmitHeader(fh, "X-YAM-Options", &options[1]);
  1173.    EmitHeader(fh, "From", comp->From ? comp->From : BuildAddrName(C->EmailAddress, C->RealName));
  1174.    if (comp->ReplyTo) EmitHeader(fh, "Reply-To", comp->ReplyTo);
  1175.    if (comp->MailTo) EmitRcptHeader(fh, "To", comp->Security == 4 ? C->ReMailer : comp->MailTo);
  1176.    if (comp->MailCC) EmitRcptHeader(fh, "CC", comp->MailCC);
  1177.    if (comp->MailBCC) EmitRcptHeader(fh, "BCC", comp->MailBCC);
  1178.    EmitHeader(fh, "Date", GetDateTime());
  1179.    fprintf(fh, "Message-ID: <%s>\n", NewID(True));
  1180.    if (comp->IRTMsgID) EmitHeader(fh, "In-Reply-To", comp->IRTMsgID);
  1181.    rcptto = comp->ReplyTo ? comp->ReplyTo : (comp->From ? comp->From : C->EmailAddress);
  1182.    if (comp->Receipt & 1) EmitHeader(fh, "Return-Receipt-To", rcptto);
  1183.    if (comp->Receipt & 2) EmitHeader(fh, "Disposition-Notification-To", rcptto);
  1184.    if (comp->Importance) EmitHeader(fh, "Importance", comp->Importance == 1 ? "High" : "Low");
  1185.    fprintf(fh, "X-Mailer: YAM %s AmigaOS E-Mail Client (c) 1995-2000 by Marcel Beck  http://www.yam.ch/\n", __YAM_VERSION);
  1186.    if (comp->UserInfo) WR_WriteUserInfo(fh);
  1187.    if (*C->Organization) EmitHeader(fh, "Organization", C->Organization);
  1188.    if (*comp->Subject) EmitHeader(fh, "Subject", comp->Subject);
  1189.    if (comp->ExtHeader) WR_EmitExtHeader(fh, comp);
  1190.  
  1191. mimebody:
  1192.    fputs("MIME-Version: 1.0\n", fh);
  1193.    sprintf(boundary, "BOUNDARY.%s", NewID(False));
  1194.    if (comp->ReportType > 0)
  1195.    {
  1196.       WR_ComposeReport(fh, comp, boundary);
  1197.       success = TRUE;
  1198.    } else if (comp->Security > SEC_NONE && comp->Security <= SEC_BOTH)
  1199.    {
  1200.       success = WR_ComposePGP(fh, comp, boundary);
  1201.    } else if (firstpart->Next)
  1202.    {
  1203.       WR_ComposeMulti(fh, comp, boundary);
  1204.       success = TRUE;
  1205.    } else
  1206.    {
  1207.       WriteContentTypeAndEncoding(fh, firstpart);
  1208.       if (comp->Security == SEC_SENDANON && comp->OldSecurity != SEC_SENDANON)
  1209.          WR_Anonymize(fh, comp->MailTo);
  1210.       fputs("\n", fh);
  1211.       EncodePart(fh, firstpart);
  1212.         success = TRUE;
  1213.    }
  1214.    CloseTempFile(tf);
  1215.    return success;
  1216. }
  1217.  
  1218. ///
  1219. /// WR_AutoSaveFile
  1220. //  Returns filename of the auto-save file
  1221. char *WR_AutoSaveFile(int winnr)
  1222. {
  1223.    static char fname[SIZE_PATHFILE];
  1224.    strmfp(fname, G->ProgDir, ".autosave");
  1225.    strcat(fname, itoa(winnr));
  1226.    strcat(fname, ".txt");
  1227.    return fname;
  1228. }
  1229. ///
  1230.  
  1231. /*** Buttons ***/
  1232. /// WR_NewMail
  1233. //  Validates write window options and generates a new message
  1234. void WR_NewMail(int mode, int winnum)
  1235. {
  1236.    struct Compose comp;
  1237.    char *addr, *er;
  1238.    static struct Mail mail;
  1239.    struct Mail *new = NULL, *mlist[3];
  1240.    int i, att = 0;
  1241.    struct WR_ClassData *wr = G->WR[winnum];
  1242.    struct WR_GUIData *gui = &wr->GUI;
  1243.    struct Folder *outfolder = FO_GetFolderByType(FT_OUTGOING, NULL);
  1244.    long winopen;
  1245.  
  1246.    get(gui->WI, MUIA_Window_Open, &winopen);
  1247.    if (winopen) set(gui->RG_PAGE, MUIA_Group_ActivePage, 0);
  1248.    /* Workaround for a MUI bug */
  1249.  
  1250.    clear(&mail, sizeof(struct Mail));
  1251.    clear(&comp, sizeof(struct Compose));
  1252.    mlist[0] = (struct Mail *)1; mlist[1] = NULL;
  1253.    get(gui->ST_TO, MUIA_String_Contents, &addr);
  1254.    er = GetStr(MSG_WR_ErrorNoRcpt);
  1255.    if (!*addr) if (MUI_Request(G->App, gui->WI, 0, NULL, GetStr(MSG_WR_NoRcptReqGad), er)) mode = WRITE_HOLD;
  1256.       else return;
  1257.    get(gui->ST_SUBJECT, MUIA_String_Contents, &comp.Subject);
  1258.    if (wr->Mode != NEW_BOUNCE && *comp.Subject == '\0')
  1259.    {
  1260.       if (C->WarnSubject && MUI_Request(G->App, gui->WI, 0, NULL, GetStr(MSG_WR_NoSubjectReqGad), GetStr(MSG_NoSubjectReq)))
  1261.       {
  1262.          set(gui->WI, MUIA_Window_ActiveObject, gui->ST_SUBJECT);
  1263.          return;
  1264.       }
  1265.    }
  1266.    Busy(GetStr(MSG_BusyComposing), "", 0, 0);
  1267.    comp.Mode = wr->Mode;
  1268.    comp.OrigMail = wr->Mail;
  1269.    comp.OldSecurity = wr->OldSecurity;
  1270.    wr->ListEntry = NULL;
  1271.    if (*addr) if (!(comp.MailTo = WR_ExpandAddresses(winnum, addr, FALSE, FALSE))) goto skip;
  1272.    if (wr->Mode != NEW_BOUNCE)
  1273.    {
  1274.       get(gui->ST_CC, MUIA_String_Contents, &addr);
  1275.       if (*addr) if (!(comp.MailCC = WR_ExpandAddresses(winnum, addr, FALSE, FALSE))) goto skip;
  1276.       get(gui->ST_BCC, MUIA_String_Contents, &addr);
  1277.       if (*addr) if (!(comp.MailBCC = WR_ExpandAddresses(winnum, addr, FALSE, FALSE))) goto skip;
  1278.       get(gui->ST_FROM, MUIA_String_Contents, &addr);
  1279.       if (*addr) if (!(comp.From = WR_ExpandAddresses(winnum, addr, FALSE, TRUE))) goto skip;
  1280.       get(gui->ST_REPLYTO, MUIA_String_Contents, &addr);
  1281.       if (*addr) if (!(comp.ReplyTo = WR_ExpandAddresses(winnum, addr, FALSE, TRUE))) goto skip;
  1282.       get(gui->ST_EXTHEADER, MUIA_String_Contents, &comp.ExtHeader);
  1283.       if (wr->ListEntry)
  1284.       {
  1285.          if (wr->ListEntry->Address[0]) comp.ReplyTo = StrBufCpy(NULL, wr->ListEntry->Address);
  1286.          if (wr->ListEntry->RealName[0]) comp.From = StrBufCpy(comp.From, BuildAddrName(C->EmailAddress, wr->ListEntry->RealName));
  1287.       }
  1288.       if (wr->MsgID[0]) comp.IRTMsgID = wr->MsgID;
  1289.       comp.Importance = 1-GetMUICycle(gui->CY_IMPORTANCE);
  1290.       if (GetMUICheck(gui->CH_RECEIPT)) comp.Receipt |= 1;
  1291.       if (GetMUICheck(gui->CH_DISPNOTI)) comp.Receipt |= 2;
  1292.       comp.Signature = GetMUIRadio(gui->RA_SIGNATURE);
  1293.       if((comp.Security = GetMUIRadio(gui->RA_SECURITY)) == SEC_DEFAULTS)
  1294.             SetDefaultSecurity(&comp);
  1295.       comp.DelSend = GetMUICheck(gui->CH_DELSEND);
  1296.       comp.UserInfo = GetMUICheck(gui->CH_ADDINFO);
  1297.       get(gui->LV_ATTACH, MUIA_List_Entries, &att);
  1298.       EditorToFile(gui->TE_EDIT, G->WR_Filename[winnum], G->TTout);
  1299.       comp.FirstPart = BuildPartsList(winnum);
  1300.       comp.FirstPart->TTable = G->TTout;
  1301.    }
  1302.  
  1303.    if (wr->Mode == NEW_EDIT)
  1304.    {
  1305.       struct Mail *edmail = wr->Mail;
  1306.       outfolder = edmail->Folder;
  1307.       if (MailExists(edmail, NULL))
  1308.       {
  1309.          comp.FH = fopen(GetMailFile(NULL, outfolder, edmail), "w");
  1310.          strcpy(mail.MailFile, edmail->MailFile);
  1311.       }
  1312.       else
  1313.       {
  1314.          wr->Mode = NEW_NEW;
  1315.          comp.FH = fopen(MA_NewMailFile(outfolder, mail.MailFile, 0), "w");
  1316.       }
  1317.    }
  1318.    else comp.FH = fopen(MA_NewMailFile(outfolder, mail.MailFile, 0), "w");
  1319.    if (comp.FH)
  1320.    {
  1321.       struct MailInfo *mi;
  1322.       struct ExtendedMail *email;
  1323.       int stat = mode == WRITE_HOLD ? STATUS_HLD : STATUS_WFS;
  1324.       BOOL done = WriteOutMessage(&comp);
  1325.       fclose(comp.FH);
  1326.       if (!done) { DeleteFile(GetMailFile(NULL, outfolder, &mail)); goto skip; }
  1327.       if (wr->Mode != NEW_BOUNCE) EndNotify(&G->WR_NRequest[winnum]);
  1328.       if ((email = MA_ExamineMail(outfolder, mail.MailFile, Status[stat], FALSE)))
  1329.       {
  1330.          new = AddMailToList((struct Mail *)email, outfolder);
  1331.          MA_FreeEMailStruct(email);
  1332.          if (FO_GetCurrentFolder() == outfolder) DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_InsertSingle, new, MUIV_NList_Insert_Sorted);
  1333.          MA_SetMailStatus(new, stat);
  1334.          if (wr->Mode == NEW_EDIT)
  1335.          {
  1336.             mi = GetMailInfo(wr->Mail);
  1337.             if (mi->Display) DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_Remove, mi->Pos);
  1338.             RemoveMailFromList(wr->Mail);
  1339.             wr->Mail = new;
  1340.             if (wr->ReadwinNum != -1) RE_ReadMessage(wr->ReadwinNum, new);
  1341.          }
  1342.       }
  1343.       if (wr->Mode != NEW_NEW)
  1344.       {
  1345.          struct Mail *m, **ml = wr->MList ? wr->MList : mlist;
  1346.          mlist[2] = wr->Mail;
  1347.          for (i = 0; i < (int)ml[0]; i++)
  1348.          {
  1349.             m = ml[i+2];
  1350.             if (!Virtual(m)) if (m->Folder->Type != FT_OUTGOING && m->Folder->Type != FT_SENT)
  1351.             {
  1352.                if (m->Status == STATUS_NEW || m->Status == STATUS_UNR)
  1353.                {
  1354.                   int mdntype = wr->Mode == NEW_REPLY ? MDN_DISP : MDN_PROC;
  1355.                   if (winnum == 2) mdntype |= MDN_AUTOACT;
  1356.                   RE_DoMDN(mdntype, m, FALSE);
  1357.                }
  1358.                switch (wr->Mode)
  1359.                {
  1360.                   case NEW_REPLY:  MA_SetMailStatus(m, STATUS_RPD);
  1361.                                    DisplayStatistics(m->Folder); break;
  1362.                   case NEW_FORWARD:
  1363.                   case NEW_BOUNCE: MA_SetMailStatus(m, STATUS_FWD);
  1364.                                    DisplayStatistics(m->Folder); break;
  1365.                }
  1366.             }
  1367.          }
  1368.       }
  1369.       switch (wr->Mode)
  1370.       {
  1371.          case NEW_NEW:     AppendLog(10, GetStr(MSG_LOG_Creating),   AddrName(new->To), new->Subject, (void *)att, ""); break;
  1372.          case NEW_REPLY:   AppendLog(11, GetStr(MSG_LOG_Replying),   AddrName(wr->MList[2]->From), wr->MList[2]->Subject, "", ""); break;
  1373.          case NEW_FORWARD: AppendLog(12, GetStr(MSG_LOG_Forwarding), AddrName(wr->MList[2]->From), wr->MList[2]->Subject, AddrName(new->To), ""); break;
  1374.          case NEW_BOUNCE:  AppendLog(13, GetStr(MSG_LOG_Bouncing),   AddrName(wr->Mail->From), wr->Mail->Subject, AddrName(new->To), ""); break;
  1375.          case NEW_EDIT:    AppendLog(14, GetStr(MSG_LOG_Editing),    AddrName(new->From), AddrName(new->To), new->Subject, ""); break;
  1376.       }
  1377.       MA_StartMacro(MACRO_POSTWRITE, itoa(winnum));
  1378.    }
  1379.    else ER_NewError(GetStr(MSG_ER_CreateMailError), NULL, NULL);
  1380.    FreePartsList(comp.FirstPart);
  1381.    if (wr->MList) free(wr->MList);
  1382.    if (mode == WRITE_SEND && new && !G->TR)
  1383.    {
  1384.       set(gui->WI, MUIA_Window_Open, FALSE);
  1385.       mlist[2] = new; MA_SendMList(mlist);
  1386.    }
  1387.    DeleteFile(WR_AutoSaveFile(winnum));
  1388.    DisposeModulePush(&G->WR[winnum]);
  1389. skip:
  1390.    FreeStrBuf(comp.MailTo);
  1391.    FreeStrBuf(comp.MailCC);
  1392.    FreeStrBuf(comp.MailBCC);
  1393.    FreeStrBuf(comp.From);
  1394.    FreeStrBuf(comp.ReplyTo);
  1395.    DisplayStatistics(outfolder);
  1396.    BusyEnd;
  1397. }
  1398.  
  1399. void SAVEDS ASM WR_NewMailFunc(REG(a1,int *arg))
  1400. {
  1401.    WR_NewMail(arg[0], arg[1]);
  1402. }
  1403. MakeHook(WR_NewMailHook, WR_NewMailFunc);
  1404.  
  1405. ///
  1406. /// WR_Cleanup
  1407. //  Terminates file notification and removes temporary files
  1408. void WR_Cleanup(int winnum)
  1409. {
  1410.    int i;
  1411.    struct Attach *att;
  1412.    if (G->WR[winnum]->Mode != NEW_BOUNCE)
  1413.    {
  1414.       EndNotify(&G->WR_NRequest[winnum]);
  1415.       DeleteFile(G->WR_Filename[winnum]);
  1416.       for (i = 0; ; i++)
  1417.       {
  1418.          DoMethod(G->WR[winnum]->GUI.LV_ATTACH, MUIM_List_GetEntry, i, &att);
  1419.          if (!att) break;
  1420.          if (att->IsTemp) DeleteFile(att->FilePath);
  1421.       }
  1422.    }
  1423. }
  1424.  
  1425. ///
  1426. /// WR_CancelFunc
  1427. //  User clicked the Cancel button
  1428. void SAVEDS ASM WR_CancelFunc(REG(a1,int *arg))
  1429. {
  1430.    int haschanged, winnum = *arg;
  1431.    if (G->WR[winnum]->Mode != NEW_BOUNCE)
  1432.    {
  1433.       if (winnum < 2)
  1434.       {
  1435.          get(G->WR[winnum]->GUI.TE_EDIT, MUIA_TextEditor_HasChanged, &haschanged);
  1436.          if (haschanged)
  1437.             switch (MUI_Request(G->App, G->WR[winnum]->GUI.WI, 0, NULL, GetStr(MSG_WR_DiscardChangesGad), GetStr(MSG_WR_DiscardChanges)))
  1438.             {
  1439.                case 0: return;
  1440.                case 1: WR_NewMail(WRITE_QUEUE, winnum);
  1441.                        return;
  1442.                case 2: break;
  1443.             }
  1444.       }
  1445.       WR_Cleanup(winnum);
  1446.    }
  1447.    DisposeModulePush(&G->WR[winnum]);
  1448. }
  1449. MakeHook(WR_CancelHook, WR_CancelFunc);
  1450.  
  1451. ///
  1452. /// WR_SaveAsFunc
  1453. //  Saves contents of internal editor to a file
  1454. void SAVEDS ASM WR_SaveAsFunc(REG(a1,int *arg))
  1455. {
  1456.    int winnum = *arg;
  1457.    set(G->WR[winnum]->GUI.RG_PAGE, MUIA_Group_ActivePage, 0);
  1458.    if (ReqFile(ASL_ATTACH, G->WR[winnum]->GUI.WI, GetStr(MSG_WR_SaveTextAs), 1, C->AttachDir, ""))
  1459.    {
  1460.       char filename[SIZE_PATHFILE];
  1461.       strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_File);
  1462.       EditorToFile(G->WR[winnum]->GUI.TE_EDIT, G->WR_Filename[winnum], NULL);
  1463.       if (!CopyFile(filename, NULL, G->WR_Filename[winnum], NULL))
  1464.          ER_NewError(GetStr(MSG_ER_CantCreateFile), filename, NULL);
  1465.    }
  1466. }
  1467. MakeHook(WR_SaveAsHook, WR_SaveAsFunc);
  1468.  
  1469. ///
  1470. /// WR_Edit
  1471. //  Launches external editor with message text
  1472. void SAVEDS ASM WR_Edit(REG(a1,int *arg))
  1473. {
  1474.    int winnum = *arg;
  1475.    long winopen;
  1476.  
  1477.    if (*(C->Editor))
  1478.    {
  1479.       char buffer[SIZE_COMMAND+SIZE_PATHFILE];
  1480.  
  1481.       get(G->WR[winnum]->GUI.WI, MUIA_Window_Open, &winopen);
  1482.       if (winopen) set(G->WR[winnum]->GUI.RG_PAGE, MUIA_Group_ActivePage, 0);
  1483.       /* Workaround for a MUI bug */
  1484.  
  1485.       EditorToFile(G->WR[winnum]->GUI.TE_EDIT, G->WR_Filename[winnum], NULL);
  1486.       sprintf(buffer,"%s \"%s\"", C->Editor, G->WR_Filename[winnum]);
  1487.       ExecuteCommand(buffer, TRUE, OUT_NIL);
  1488.    }
  1489. }
  1490. MakeHook(WR_EditHook, WR_Edit);
  1491.  
  1492. ///
  1493. /// WR_AddFileFunc
  1494. //  Adds one or more files to the attachment list
  1495. void SAVEDS ASM WR_AddFileFunc(REG(a1,int *arg))
  1496. {
  1497.    int i, winnum = *arg;
  1498.    char filename[SIZE_PATHFILE];
  1499.    struct FileRequester *ar = G->ASLReq[ASL_ATTACH];
  1500.  
  1501.    if (ReqFile(ASL_ATTACH, G->WR[winnum]->GUI.WI, GetStr(MSG_WR_AddFile), 2, C->AttachDir, ""))
  1502.       if (!ar->fr_NumArgs)
  1503.       {
  1504.          strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_File);
  1505.          WR_AddFileToList(winnum, filename, NULL, FALSE);
  1506.       }
  1507.       else for (i = 0; i < ar->fr_NumArgs; i++)
  1508.       {
  1509.          strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_ArgList[i].wa_Name);
  1510.          WR_AddFileToList(winnum, filename, NULL, FALSE);
  1511.       }
  1512. }
  1513. MakeHook(WR_AddFileHook, WR_AddFileFunc);
  1514.  
  1515. ///
  1516. /// WR_AddArchiveFunc
  1517. //  Creates an archive of one or more files and adds it to the attachment list
  1518. void SAVEDS ASM WR_AddArchiveFunc(REG(a1,int *arg))
  1519. {
  1520.    int i, winnum = *arg;
  1521.    static char chr[2] = { 0,0 };
  1522.    char *src, *dst, filename[SIZE_PATHFILE], arcpath[SIZE_PATHFILE], arcname[SIZE_FILE];
  1523.    struct TempFile *tf = NULL;
  1524.    struct FileRequester *ar = G->ASLReq[ASL_ATTACH];
  1525.    BPTR olddir, filedir;
  1526.  
  1527.    if (ReqFile(ASL_ATTACH, G->WR[winnum]->GUI.WI, GetStr(MSG_WR_AddFile), 2, C->AttachDir, ""))
  1528.    {
  1529.       strsfn(ar->fr_ArgList[0].wa_Name, NULL, NULL, arcname, NULL);
  1530.       if (!*arcname) strsfn(ar->fr_ArgList[0].wa_Name, NULL, NULL, NULL, arcname);
  1531.       if (!StringRequest(arcname, SIZE_FILE, GetStr(MSG_WR_CreateArc), GetStr(MSG_WR_CreateArcReq), GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), FALSE, G->WR[winnum]->GUI.WI)) return;
  1532.       strmfp(filename, C->TempDir, arcname);
  1533.       sprintf(arcpath, strchr(filename, ' ') ? "\"%s\"" : "%s", filename);
  1534.       if (strstr(C->PackerCommand, "%l")) if ((tf = OpenTempFile("w")))
  1535.       {
  1536.          for (i = 0; i < ar->fr_NumArgs; i++)
  1537.          {
  1538. //            strmfp(filename, ar->fr_Drawer, ar->fr_ArgList[i].wa_Name);
  1539. //            fprintf(tf->FP, strchr(filename, ' ') ? "\"%s\"\n" : "%s\n", filename);
  1540.             fprintf(tf->FP, strchr(ar->fr_ArgList[i].wa_Name, ' ') ? "\"%s\"\n" : "%s\n", ar->fr_ArgList[i].wa_Name);
  1541.          }
  1542.          fclose(tf->FP); tf->FP = NULL;
  1543.       }
  1544.       dst = AllocStrBuf(SIZE_DEFAULT);
  1545.       for (src = C->PackerCommand; *src; src++)
  1546.          if (*src == '%') switch (*++src)
  1547.          {
  1548.             case '%': dst = StrBufCat(dst, "%"); break;
  1549.             case 'a': dst = StrBufCat(dst, arcpath); break;
  1550.             case 'l': dst = StrBufCat(dst, tf->Filename); break;
  1551.             case 'f': for (i = 0; i < ar->fr_NumArgs; i++)
  1552.                       {
  1553. //                         strcpy(filename, "\"");
  1554. //                         strmfp(&filename[1], ar->fr_Drawer, ar->fr_ArgList[i].wa_Name);
  1555. //                         strcat(filename, "\" ");
  1556.                          sprintf(filename, "\"%s\"", ar->fr_ArgList[i].wa_Name);
  1557.                          dst = StrBufCat(dst, filename);
  1558.                       }
  1559.                       break;
  1560.          }
  1561.          else
  1562.          {
  1563.             chr[0] = *src;
  1564.             dst = StrBufCat(dst, chr);
  1565.          }
  1566.       filedir = Lock(ar->fr_Drawer, ACCESS_READ); olddir = CurrentDir(filedir);
  1567.       ExecuteCommand(dst, FALSE, OUT_NIL);
  1568.       CurrentDir(olddir); UnLock(filedir);
  1569.       FreeStrBuf(dst);
  1570.       CloseTempFile(tf);
  1571.       strcpy(filename, arcpath);
  1572.       if (FileSize(filename) == -1)
  1573.       {
  1574.          sprintf(filename, "%s.lha", arcpath);
  1575.          if (FileSize(filename) == -1)
  1576.          {
  1577.             sprintf(filename, "%s.lzx", arcpath);
  1578.             if (FileSize(filename) == -1)
  1579.                sprintf(filename, "%s.zip", arcpath);
  1580.          }
  1581.       }
  1582.       WR_AddFileToList(winnum, filename, NULL, TRUE);
  1583.    }
  1584. }
  1585. MakeHook(WR_AddArchiveHook, WR_AddArchiveFunc);
  1586.  
  1587. ///
  1588. /// WR_DisplayFile
  1589. //  Displays an attached file using a MIME viewer
  1590. void SAVEDS ASM WR_DisplayFile(REG(a1,int *arg))
  1591. {
  1592.    struct Attach *attach = NULL;
  1593.  
  1594.    DoMethod(G->WR[*arg]->GUI.LV_ATTACH, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &attach);
  1595.    if (attach) RE_DisplayMIME(attach->FilePath, attach->ContentType);
  1596. }
  1597. MakeHook(WR_DisplayFileHook, WR_DisplayFile);
  1598.  
  1599. ///
  1600. /// WR_ChangeSignatureFunc
  1601. //  Changes the current signature
  1602. void SAVEDS ASM WR_ChangeSignatureFunc(REG(a1,int *arg))
  1603. {
  1604.    struct TempFile *tf;
  1605.    int signat = arg[0], winnum = arg[1];
  1606.    char buffer[SIZE_LINE];
  1607.    FILE *in, *out;
  1608.  
  1609.    if ((tf = OpenTempFile(NULL)))
  1610.    {
  1611.       EditorToFile(G->WR[winnum]->GUI.TE_EDIT, tf->Filename, NULL);
  1612.       if ((in = fopen(tf->Filename, "r")))
  1613.       {
  1614.          if ((out = fopen(G->WR_Filename[winnum], "w")))
  1615.          {
  1616.             while (fgets(buffer, SIZE_LINE, in))
  1617.                if (strcmp(buffer, "-- \n")) fputs(buffer, out); else break;
  1618.             if (signat) WR_WriteSignature(out, signat-1);
  1619.             fclose(out);
  1620.          }
  1621.          fclose(in);
  1622.       }
  1623.       CloseTempFile(tf);;
  1624.    }
  1625. }
  1626. MakeHook(WR_ChangeSignatureHook, WR_ChangeSignatureFunc);
  1627. ///
  1628.  
  1629. /*** Menus ***/
  1630. /// WR_TransformText
  1631. //  Inserts or pastes text as plain, ROT13 or quoted
  1632. LOCAL char *WR_TransformText(char *source, int mode, char *qtext)
  1633. {
  1634.    FILE *fp;
  1635.    char *dest = NULL;
  1636.    int ch, i, size = FileSize(source), pos = 0, p = 0, qtextlen = strlen(qtext);
  1637.    BOOL quote = (mode == ED_INSQUOT || mode == ED_PASQUOT ||
  1638.                  mode == ED_INSALTQUOT || mode == ED_PASALTQUOT);
  1639.    if (size > 0)
  1640.    {
  1641.       size += SIZE_DEFAULT;
  1642.       if (quote) size += size/20*qtextlen;
  1643.       if ((dest = calloc(size, 1)))
  1644.       {
  1645.          if ((fp = fopen(source, "r")))
  1646.          {
  1647.             while ((ch = fgetc(fp)) != EOF)
  1648.             {
  1649.                if (!pos && quote)
  1650.                {
  1651.                   if (p+qtextlen > size-2) dest = realloc(dest,(size += SIZE_LARGE));
  1652.                   for (i = 0; i < qtextlen; i++) dest[p++] = qtext[i];
  1653.                   dest[p++] = ' ';
  1654.                }
  1655.                if (ch == '\n') pos = 0; else ++pos;
  1656.                if (mode == ED_INSROT13 || mode == ED_PASROT13)
  1657.                {
  1658.                   if (ch >= 'a' && ch <= 'z') if ((ch += 13) > 'z') ch -= 26;
  1659.                   if (ch >= 'A' && ch <= 'Z') if ((ch += 13) > 'Z') ch -= 26;
  1660.                }
  1661.                if (p > size-3) dest = realloc(dest,(size += SIZE_LARGE));
  1662.                dest[p++] = ch;
  1663.             }
  1664.             dest[p] = 0;
  1665.             fclose(fp);
  1666.          }
  1667.       }
  1668.    }
  1669.    return dest;
  1670. }
  1671.  
  1672. ///
  1673. /// WR_InsertSeparator
  1674. //  Inserts a separator bar at the cursor position
  1675. void SAVEDS ASM WR_InsertSeparatorFunc(REG(a1,int *arg))
  1676. {
  1677.    APTR ed = G->WR[arg[1]]->GUI.TE_EDIT;
  1678.    set(ed, MUIA_TextEditor_ImportHook, MUIV_TextEditor_ImportHook_Plain);
  1679.    DoMethod(ed, MUIM_TextEditor_InsertText, arg[0] ? "\n\033c\033[s:18]\n" : "\n\033c\033[s:2]\n");
  1680.    set(ed, MUIA_TextEditor_ImportHook, MUIV_TextEditor_ImportHook_EMail);
  1681. }
  1682. MakeHook(WR_InsertSeparatorHook, WR_InsertSeparatorFunc);
  1683.  
  1684. ///
  1685. /// WR_EditorCmd
  1686. //  Inserts file or clipboard into editor
  1687. void SAVEDS ASM WR_EditorCmd(REG(a1,int *arg))
  1688. {
  1689.    int cmd = arg[0], winnum = arg[1];
  1690.    char *text, *quotetext, filename[SIZE_PATHFILE];
  1691.    struct TempFile *tf;
  1692.    struct WR_ClassData *wr = G->WR[winnum];
  1693.  
  1694.     quotetext = (cmd == ED_INSALTQUOT || cmd == ED_PASALTQUOT) ?
  1695.                         wr->AltQuoteText : wr->QuoteText;
  1696.    switch(cmd)
  1697.    {
  1698.       case ED_INSERT:
  1699.       case ED_INSQUOT:
  1700.       case ED_INSALTQUOT:
  1701.       case ED_INSROT13:
  1702.       case ED_OPEN:
  1703.          if (!ReqFile(ASL_ATTACH, wr->GUI.WI, GetStr(MSG_WR_InsertFile), 0, C->AttachDir, "")) return;
  1704.          strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_File);
  1705.              text = WR_TransformText(filename, cmd, quotetext);
  1706.          break;
  1707.       default:
  1708.          if (!(tf = OpenTempFile("w"))) return;
  1709.          DumpClipboard(tf->FP);
  1710.          fclose(tf->FP); tf->FP = NULL;
  1711.              text = WR_TransformText(tf->Filename, cmd, quotetext);
  1712.          CloseTempFile(tf);
  1713.          break;
  1714.    }
  1715.    if(text)
  1716.    {
  1717.       if (cmd == ED_OPEN) DoMethod(wr->GUI.TE_EDIT, MUIM_TextEditor_ClearText);
  1718.       DoMethod(wr->GUI.TE_EDIT, MUIM_TextEditor_InsertText, text);
  1719.       free(text);
  1720.    }
  1721. }
  1722. MakeHook(WR_EditorCmdHook, WR_EditorCmd);
  1723.  
  1724. ///
  1725. /// WR_AddClipboardFunc
  1726. //  Adds contents of clipboard as attachment
  1727. void SAVEDS ASM WR_AddClipboardFunc(REG(a1,int *arg))
  1728. {
  1729.    int winnum = *arg;
  1730.    struct TempFile *tf = OpenTempFile("w");
  1731.    if (DumpClipboard(tf->FP))
  1732.    {
  1733.       fclose(tf->FP); tf->FP = NULL;
  1734.       WR_AddFileToList(winnum, tf->Filename, "clipboard.text", TRUE);
  1735.       free(tf);
  1736.       return;
  1737.    }
  1738.    CloseTempFile(tf);
  1739. }
  1740. MakeHook(WR_AddClipboardHook, WR_AddClipboardFunc);
  1741.  
  1742. ///
  1743. /// WR_AddPGPKeyFunc
  1744. //  Adds ASCII version of user's public PGP key as attachment
  1745. void SAVEDS ASM WR_AddPGPKeyFunc(REG(a1,int *arg))
  1746. {
  1747.    int winnum = *arg;
  1748.    char *myid = *C->MyPGPID ? C->MyPGPID : C->EmailAddress;
  1749.    char options[SIZE_LARGE], *fname = "T:PubKey.asc";
  1750.    sprintf(options, (G->PGPVersion == 5) ? "-x %s -o %s +force +batchmode=1" : "-kxa %s %s +f +bat", myid, fname);
  1751.    if (!PGPCommand((G->PGPVersion == 5) ? "pgpk" : "pgp", options, 0)) if (FileSize(fname) > 0)
  1752.    {
  1753.       WR_AddFileToList(winnum, fname, NULL, TRUE);
  1754.       setstring(G->WR[winnum]->GUI.ST_CTYPE, "application/pgp-keys");
  1755.    }
  1756.    else ER_NewError(GetStr(MSG_ER_ErrorAppendKey), myid, NULL);
  1757. }
  1758. MakeHook(WR_AddPGPKeyHook, WR_AddPGPKeyFunc);
  1759. ///
  1760.  
  1761. /*** Open ***/
  1762. /// WR_Open
  1763. //  Initializes a write window
  1764. int WR_Open(int winnum, BOOL bounce)
  1765. {
  1766.    /* winnum:
  1767.       -1 - a new window should be opened
  1768.        2 - window should be opened in "quiet mode"
  1769.  
  1770.       G->WR[0]: 1st possible window.
  1771.       G->WR[1]: 2nd possible window.
  1772.       G->WR[2]: Quiet window (last).
  1773.    */
  1774.  
  1775.    /* Find first un-used window and set winnum accordingly (or return -1
  1776.       if they are all taken). */
  1777.    if (winnum == -1) if (G->WR[winnum = 0]) if (G->WR[winnum = 1]) return -1;
  1778.  
  1779.    G->WR[winnum] = bounce ? WR_NewBounce(winnum) : WR_New(winnum);
  1780.    if (!G->WR[winnum]) return -1;
  1781.    if (!bounce)
  1782.    {
  1783.       struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  1784.       setstring(gui->ST_FROM, BuildAddrName(C->EmailAddress, C->RealName));
  1785.       setstring(gui->ST_REPLYTO, C->ReplyTo);
  1786.       setstring(gui->ST_EXTHEADER, C->ExtraHeaders);
  1787.       setcheckmark(gui->CH_DELSEND, !C->SaveSent);
  1788.       setcheckmark(gui->CH_ADDINFO, C->AddMyInfo);
  1789.    }
  1790.    MA_StartMacro(MACRO_PREWRITE, itoa(winnum));
  1791.    return winnum;
  1792. }
  1793.  
  1794. ///
  1795. /// WR_SetupOldMail
  1796. //  When editing a message, sets write window options to old values
  1797. void WR_SetupOldMail(int winnum)
  1798. {
  1799.    static struct Attach attach;
  1800.    struct Part *part = G->RE[4]->FirstPart->Next;
  1801.  
  1802.    if (part) for (part = part->Next; part; part = part->Next)
  1803.       if (stricmp(part->ContentType, "application/pgp-signature"))
  1804.       {
  1805.          Busy(GetStr(MSG_BusyDecSaving), "", 0, 0);
  1806.          RE_DecodePart(part);
  1807.          clear(&attach, sizeof(struct Attach));
  1808.          attach.Size = part->Size;
  1809.          attach.IsMIME = part->EncodingCode != ENC_UUE;
  1810.          attach.IsTemp = TRUE;
  1811.          if (part->Name) stccpy(attach.Name, part->Name, SIZE_FILE);
  1812.          strcpy(attach.FilePath, part->Filename);
  1813.          *part->Filename = 0;
  1814.          stccpy(attach.ContentType, part->ContentType, SIZE_CTYPE);
  1815.          stccpy(attach.Description, part->Description, SIZE_DEFAULT);
  1816.          DoMethod(G->WR[winnum]->GUI.LV_ATTACH, MUIM_List_InsertSingle, &attach, MUIV_List_Insert_Bottom);
  1817.          BusyEnd;
  1818.       }
  1819. }
  1820.  
  1821. ///
  1822. /// WR_UpdateTitleFunc
  1823. //  Shows cursor coordinates
  1824. void SAVEDS ASM WR_UpdateWTitleFunc(REG(a1,int *arg))
  1825. {
  1826.    struct WR_ClassData *wr = G->WR[*arg];
  1827.    APTR ed = wr->GUI.TE_EDIT;
  1828.  
  1829.    sprintf(wr->WTitle, "%03ld\n%03ld", GetMUI(ed,MUIA_TextEditor_CursorY)+1, GetMUI(ed,MUIA_TextEditor_CursorX)+1);
  1830.    set(wr->GUI.TX_POSI, MUIA_Text_Contents, wr->WTitle);
  1831. }
  1832. MakeHook(WR_UpdateWTitleHook,WR_UpdateWTitleFunc);
  1833. ///
  1834.  
  1835. /*** Hooks ***/
  1836. /// WR_AppFunc
  1837. //  Handles Drag&Drop
  1838. void WR_App(int winnum, struct AppMessage *amsg)
  1839. {
  1840.    struct WBArg *ap;
  1841.    int i, mode;
  1842.    char buf[SIZE_PATHFILE];
  1843.  
  1844.    get(G->WR[winnum]->GUI.RG_PAGE, MUIA_Group_ActivePage, &mode);
  1845.    for (i = 0; i < amsg->am_NumArgs; i++)
  1846.    {
  1847.       ap = &amsg->am_ArgList[i];
  1848.       NameFromLock(ap->wa_Lock, buf, SIZE_PATHFILE);
  1849.       AddPart(buf, ap->wa_Name, SIZE_PATHFILE);
  1850.       if (!mode)
  1851.       {
  1852.          FILE *fh;
  1853.          int len, j, notascii = 0;
  1854.          char buffer[SIZE_LARGE];
  1855.          if ((fh = fopen(buf, "r")))
  1856.          {
  1857.             len = fread(buffer, 1, SIZE_LARGE-1, fh);
  1858.             buffer[len] = 0;
  1859.             fclose(fh);
  1860.             for (j = 0; j < len; j++) if ((int)buffer[j] < 32 || (int)buffer[j] > 127) if (buffer[j] != '\t' && buffer[j] != '\n') notascii++;
  1861.             if (notascii) if (len/notascii <= 16) mode = 1;
  1862.          }
  1863.       }
  1864.       if (!mode)
  1865.       {
  1866.          char *text = WR_TransformText(buf, ED_INSERT, "");
  1867.          if (text) DoMethod(G->WR[winnum]->GUI.TE_EDIT, MUIM_TextEditor_InsertText, text);
  1868.          free(text);
  1869.       }
  1870.       else WR_AddFileToList(winnum, buf, NULL, FALSE);
  1871.    }
  1872. }
  1873.  
  1874. LONG SAVEDS ASM WR_AppFunc(REG(a1,ULONG *arg))
  1875. {
  1876.    WR_App((int)arg[1],  (struct AppMessage *)arg[0]);
  1877.    return 0;
  1878. }
  1879. MakeHook(WR_AppHook, WR_AppFunc);
  1880.  
  1881. ///
  1882. /// WR_LV_ConFunc
  1883. //  Attachment listview construct hook
  1884. struct Attach * SAVEDS ASM WR_LV_ConFunc(REG(a1,struct Attach *attach))
  1885. {
  1886.    struct Attach *entry = malloc(sizeof(struct Attach));
  1887.    *entry = *attach;
  1888.    return entry;
  1889. }
  1890. MakeHook(WR_LV_ConFuncHook, WR_LV_ConFunc);
  1891.  
  1892. ///
  1893. /// WR_LV_DspFunc
  1894. //  Attachment listview display hook
  1895. long SAVEDS ASM WR_LV_DspFunc(REG(a2,char **array), REG(a1,struct Attach *entry))
  1896. {
  1897.    static char dispsz[SIZE_SMALL];
  1898.    if (entry)
  1899.    {
  1900.       array[0] = entry->Name;
  1901.       sprintf(array[1] = dispsz, "%d", entry->Size);
  1902.       array[2] = DescribeCT(entry->ContentType);
  1903.       array[3] = entry->IsMIME ? "MIME" : "UU";
  1904.       array[4] = entry->Description;
  1905.    }
  1906.    else 
  1907.    {
  1908.       array[0] = GetStr(MSG_WR_TitleFile); 
  1909.       array[1] = GetStr(MSG_WR_TitleSize);
  1910.       array[2] = GetStr(MSG_WR_TitleContents);
  1911.       array[3] = GetStr(MSG_WR_TitleEncoding);
  1912.       array[4] = GetStr(MSG_WR_TitleDescription);
  1913.    }
  1914.    return 0;
  1915. }
  1916. MakeHook(WR_LV_DspFuncHook, WR_LV_DspFunc);
  1917. ///
  1918.  
  1919. /*** GUI ***/
  1920. /// WR_SharedSetup
  1921. //  Common setup for write and bounce windows
  1922. LOCAL void WR_SharedSetup(struct WR_ClassData *data, int winnum)
  1923. {
  1924.    SetHelp(data->GUI.ST_TO      ,MSG_HELP_WR_ST_TO      );
  1925.    SetHelp(data->GUI.BT_QUEUE   ,MSG_HELP_WR_BT_QUEUE   );
  1926.    SetHelp(data->GUI.BT_HOLD    ,MSG_HELP_WR_BT_HOLD    );
  1927.    SetHelp(data->GUI.BT_SEND    ,MSG_HELP_WR_BT_SEND    );
  1928.    SetHelp(data->GUI.BT_CANCEL  ,MSG_HELP_WR_BT_CANCEL  );
  1929.    DoMethod(data->GUI.BT_HOLD    ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_NewMailHook,WRITE_HOLD,winnum);
  1930.    DoMethod(data->GUI.BT_QUEUE   ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_NewMailHook,WRITE_QUEUE,winnum);
  1931.    DoMethod(data->GUI.BT_SEND    ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_NewMailHook,WRITE_SEND,winnum);
  1932.    DoMethod(data->GUI.BT_CANCEL  ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_CancelHook,winnum);
  1933.    DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_CloseRequest ,TRUE          ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_CancelHook,winnum);
  1934. }
  1935.  
  1936. ///
  1937. /// MakeAddressField
  1938. //  Creates a recipient field
  1939. LOCAL APTR MakeAddressField(APTR *string, char *label, APTR help, int abmode, int winnum, BOOL allowmulti)
  1940. {
  1941.    APTR obj, bt_ver, bt_adr;
  1942.    if ((obj = HGroup,
  1943.       GroupSpacing(1),
  1944.       Child, *string = NewObject(CL_DDString->mcc_Class, NULL,
  1945.          MUIA_ControlChar, ShortCut(label),
  1946.          MUIA_UserData, allowmulti,
  1947.       End,
  1948.       Child, bt_ver = PopButton(MUII_ArrowLeft),
  1949.       Child, bt_adr = PopButton(MUII_PopUp),
  1950.    End))
  1951.    {
  1952.       set(bt_ver, MUIA_CycleChain, TRUE);
  1953.       set(bt_adr, MUIA_CycleChain, TRUE);
  1954.       SetHelp(*string,help);
  1955.       SetHelp(bt_ver, MSG_HELP_WR_BT_VER);
  1956.       SetHelp(bt_adr, MSG_HELP_WR_BT_ADR);
  1957.       DoMethod(*string,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,MUIV_Notify_Window,5,MUIM_CallHook,&WR_VerifyAutoHook,*string,winnum,!allowmulti);
  1958.       DoMethod(bt_ver,MUIM_Notify,MUIA_Pressed,FALSE,MUIV_Notify_Application,5,MUIM_CallHook,&WR_VerifyManualHook,*string,winnum,!allowmulti);
  1959.       DoMethod(bt_adr,MUIM_Notify,MUIA_Pressed,FALSE,MUIV_Notify_Application,4,MUIM_CallHook,&AB_OpenHook,abmode,winnum);
  1960.    }
  1961.    return obj;
  1962. }
  1963.  
  1964. ///
  1965. /// WR_New
  1966. //  Creates a write window
  1967. enum { WMEN_NEW=1,WMEN_OPEN,WMEN_INSFILE,WMEN_SAVEAS,WMEN_INSQUOT,WMEN_INSALTQUOT,
  1968.        WMEN_INSROT13,WMEN_EDIT,WMEN_CUT,WMEN_COPY,WMEN_PASTE,
  1969.        WMEN_PASQUOT,WMEN_PASALTQUOT,WMEN_PASROT13,WMEN_DICT,WMEN_STYLE1,WMEN_STYLE2,WMEN_STYLE3,
  1970.        WMEN_STYLE4,WMEN_EMOT0,WMEN_EMOT1,WMEN_EMOT2,WMEN_EMOT3,WMEN_UNDO,WMEN_REDO,
  1971.        WMEN_AUTOSP,WMEN_SEP0,WMEN_SEP1,WMEN_ADDFILE, WMEN_ADDCLIP, WMEN_ADDPGP,
  1972.        WMEN_DELSEND,WMEN_RECEIPT,WMEN_DISPNOTI,WMEN_ADDINFO,WMEN_IMPORT0,WMEN_IMPORT1,
  1973.        WMEN_IMPORT2,WMEN_SIGN0,WMEN_SIGN1,WMEN_SIGN2,WMEN_SIGN3,
  1974.        WMEN_SECUR0,WMEN_SECUR1,WMEN_SECUR2,WMEN_SECUR3,WMEN_SECUR4, WMEN_SECUR5 };
  1975. extern long cmap[8];
  1976.  
  1977. struct WR_ClassData *WR_New(int winnum)
  1978. {
  1979.    struct WR_ClassData *data;
  1980.  
  1981.    if ((data = calloc(1,sizeof(struct WR_ClassData))))
  1982.    {
  1983.       static char *rtitles[4]={NULL}, *encoding[3], *security[SEC_MAXDUMMY+1], *priority[4], *signat[5];
  1984.       static char *emoticons[4] = { ":-)", ":-|", ":-(", ";-)" };
  1985.       APTR sec_menus[SEC_MAXDUMMY];
  1986.       APTR mi_copy, mi_cut, mi_redo, mi_undo, mi_bold, mi_italic, mi_underl, mi_color;
  1987.       APTR strip, mi_autospell, mi_delsend, mi_receipt, mi_dispnoti, mi_addinfo;
  1988.       APTR slider = ScrollbarObject, End;
  1989.       APTR tb_butt[13] = { MSG_WR_TBEditor,MSG_WR_TBInsert,MSG_Space,
  1990.                            MSG_WR_TBCut,MSG_WR_TBCopy,MSG_WR_TBPaste,MSG_WR_TBUndo,MSG_Space,
  1991.                            MSG_WR_TBBold,MSG_WR_TBItalic,MSG_WR_TBUnderlined,MSG_WR_TBColored,NULL };
  1992.       APTR tb_help[13] = { MSG_HELP_WR_BT_EDITOR,MSG_HELP_WR_BT_LOAD,NULL,
  1993.                            MSG_HELP_WR_BT_CUT,MSG_HELP_WR_BT_COPY,MSG_HELP_WR_BT_PASTE,MSG_HELP_WR_BT_UNDO,NULL,
  1994.                            MSG_HELP_WR_BT_BOLD,MSG_HELP_WR_BT_ITALIC,MSG_HELP_WR_BT_UNDERL,MSG_HELP_WR_BT_COLOR,NULL };
  1995.       int i, spell;
  1996.       for (i = 0; i < 13; i++) SetupToolbar(&(data->GUI.TB_TOOLBAR[i]), tb_butt[i]?(tb_butt[i]==MSG_Space?"":GetStr(tb_butt[i])):NULL, tb_help[i]?GetStr(tb_help[i]):NULL, (i>=8 && i<=11)?TDF_TOGGLE:0);
  1997.         if(NULL == rtitles[0])    // only initialize static data on first call
  1998.         {
  1999.             rtitles[0] = GetStr(MSG_Message);
  2000.             rtitles[1] = GetStr(MSG_Attachments);
  2001.             rtitles[2] = GetStr(MSG_Options);
  2002.             rtitles[3] = NULL;
  2003.             encoding[0] = "Base64/QP";
  2004.             encoding[1] = "UUencode";
  2005.             encoding[2] = NULL;
  2006.             security[SEC_NONE]    = GetStr(MSG_WR_SecNone);
  2007.             security[SEC_SIGN]    = GetStr(MSG_WR_SecSign);
  2008.             security[SEC_ENCRYPT] = GetStr(MSG_WR_SecEncrypt);
  2009.             security[SEC_BOTH]    = GetStr(MSG_WR_SecBoth);
  2010.             security[SEC_SENDANON]= GetStr(MSG_WR_SecAnon);
  2011.             security[SEC_DEFAULTS]= GetStr(MSG_WR_SecDefaults);
  2012.             security[SEC_MAXDUMMY]= NULL;
  2013.             priority[0] = GetStr(MSG_WR_ImpHigh);
  2014.             priority[1] = GetStr(MSG_WR_ImpNormal);
  2015.             priority[2] = GetStr(MSG_WR_ImpLow);
  2016.             priority[3] = NULL;
  2017.             signat[0] = GetStr(MSG_WR_NoSig);
  2018.             signat[1] = GetStr(MSG_WR_DefSig);
  2019.             signat[2] = GetStr(MSG_WR_AltSig1);
  2020.             signat[3] = GetStr(MSG_WR_AltSig2);
  2021.             signat[4] = NULL;
  2022.         }
  2023.       data->GUI.WI = WindowObject,
  2024.          MUIA_Window_Title, GetStr(MSG_WR_WriteWT),
  2025.          MUIA_HelpNode, "WR_W",
  2026.          MUIA_Window_ID, MAKE_ID('W','R','I','T'),
  2027.          MUIA_Window_Menustrip, strip = MenustripObject,
  2028.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_WR_Text),
  2029.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_New), MUIA_Menuitem_Shortcut,"N", MUIA_UserData,WMEN_NEW, End,
  2030.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Open), MUIA_Menuitem_Shortcut,"O", MUIA_UserData,WMEN_OPEN, End,
  2031.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_InsertAs),
  2032.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Plain), MUIA_Menuitem_Shortcut,"P", MUIA_UserData,WMEN_INSFILE, End,
  2033.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Quoted), MUIA_UserData,WMEN_INSQUOT, End,
  2034.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_AltQuoted), MUIA_UserData,WMEN_INSALTQUOT, End,
  2035.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_ROT13), MUIA_UserData,WMEN_INSROT13, End,
  2036.                End,
  2037.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  2038.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_SaveAs), MUIA_UserData,WMEN_SAVEAS, End,
  2039.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  2040.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_LaunchEd), MUIA_Menuitem_Shortcut,"E", MUIA_UserData,WMEN_EDIT, End,
  2041.             End,
  2042.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_WR_Edit),
  2043.                MUIA_Family_Child, mi_cut = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MCut), MUIA_Menuitem_Shortcut,"ramiga X", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_CUT, End,
  2044.                MUIA_Family_Child, mi_copy = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MCopy), MUIA_Menuitem_Shortcut,"ramiga C", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_COPY, End,
  2045.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MPaste), MUIA_Menuitem_Shortcut,"ramiga V", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_PASTE, End,
  2046.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_PasteAs),
  2047.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Quoted), MUIA_Menuitem_Shortcut,"Q", MUIA_UserData,WMEN_PASQUOT, End,
  2048.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_AltQuoted), MUIA_UserData,WMEN_PASALTQUOT, End,
  2049.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_ROT13), MUIA_UserData,WMEN_PASROT13, End,
  2050.                End,
  2051.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  2052.                MUIA_Family_Child, mi_undo = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MUndo), MUIA_Menuitem_Shortcut,"ramiga Z", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_UNDO, End,
  2053.                MUIA_Family_Child, mi_redo = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Redo), WMEN_REDO, End,
  2054.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  2055.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Dictionary), MUIA_Menuitem_Shortcut,"D", MUIA_UserData,WMEN_DICT, End,
  2056.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Textstyle),
  2057.                   MUIA_Family_Child, mi_bold = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Bold), MUIA_Menuitem_Shortcut,"B", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE1, End,
  2058.                   MUIA_Family_Child, mi_italic = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Italic), MUIA_Menuitem_Shortcut,"I", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE2, End,
  2059.                   MUIA_Family_Child, mi_underl = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Underlined), MUIA_Menuitem_Shortcut,"U", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE3, End,
  2060.                   MUIA_Family_Child, mi_color = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Colored), MUIA_Menuitem_Shortcut,"A", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE4, End,
  2061.                End,
  2062.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Separators),
  2063.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title, GetStr(MSG_WR_Thin), MUIA_Menuitem_Shortcut,"-", MUIA_UserData,WMEN_SEP0, End,
  2064.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title, GetStr(MSG_WR_Thick), MUIA_Menuitem_Shortcut,"=", MUIA_UserData,WMEN_SEP1, End,
  2065.                End,
  2066.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Emoticons),
  2067.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Happy), MUIA_UserData,WMEN_EMOT0, End,
  2068.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Indifferent), MUIA_UserData,WMEN_EMOT1, End,
  2069.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Sad), MUIA_UserData,WMEN_EMOT2, End,
  2070.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Ironic), MUIA_UserData,WMEN_EMOT3, End,
  2071.                End,
  2072.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,NM_BARLABEL, End,
  2073.                MUIA_Family_Child, mi_autospell = MenuitemObject, MUIA_Menuitem_Title, GetStr(MSG_WR_SpellCheck), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_AUTOSP, End,
  2074.             End,
  2075.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_Attachments),
  2076.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MAddFile), MUIA_Menuitem_Shortcut,"F", MUIA_UserData,WMEN_ADDFILE, End,
  2077.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_AddCB), MUIA_UserData,WMEN_ADDCLIP, End,
  2078.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_AddKey), MUIA_UserData,WMEN_ADDPGP, End,
  2079.             End,
  2080.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_Options),
  2081.                MUIA_Family_Child, mi_delsend = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MDelSend), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_DELSEND, End,
  2082.                MUIA_Family_Child, mi_receipt = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MReceipt), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_RECEIPT, End,
  2083.                MUIA_Family_Child, mi_dispnoti= MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MGetMDN),  MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_DISPNOTI, End,
  2084.                MUIA_Family_Child, mi_addinfo = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MAddInfo), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_ADDINFO, End,
  2085.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MImportance),
  2086.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,priority[0], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x06, MUIA_UserData,WMEN_IMPORT0, End,
  2087.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,priority[1], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x05, MUIA_Menuitem_Checked,TRUE, MUIA_UserData,WMEN_IMPORT1, End,
  2088.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,priority[2], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x03, MUIA_UserData,WMEN_IMPORT2, End,
  2089.                End,
  2090.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_CO_CrdSignature),
  2091.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[0], MUIA_Menuitem_Shortcut,"0", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0E, MUIA_Menuitem_Checked,!C->UseSignature, MUIA_UserData,WMEN_SIGN0, End,
  2092.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[1], MUIA_Menuitem_Shortcut,"7", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0D, MUIA_Menuitem_Checked,C->UseSignature, MUIA_UserData,WMEN_SIGN1, End,
  2093.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[2], MUIA_Menuitem_Shortcut,"8", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0B, MUIA_UserData,WMEN_SIGN2, End,
  2094.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[3], MUIA_Menuitem_Shortcut,"9", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x07, MUIA_UserData,WMEN_SIGN3, End,
  2095.                End,
  2096.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_CO_CrdSecurity),
  2097.                   MUIA_Family_Child, sec_menus[SEC_NONE]     = MenuitemObject, MUIA_Menuitem_Title,security[SEC_NONE]    , MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x3E, MUIA_UserData,WMEN_SECUR0, End,
  2098.                   MUIA_Family_Child, sec_menus[SEC_SIGN]     = MenuitemObject, MUIA_Menuitem_Title,security[SEC_SIGN]    , MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x3D, MUIA_UserData,WMEN_SECUR1, End,
  2099.                   MUIA_Family_Child, sec_menus[SEC_ENCRYPT]  = MenuitemObject, MUIA_Menuitem_Title,security[SEC_ENCRYPT] , MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x3B, MUIA_UserData,WMEN_SECUR2, End,
  2100.                   MUIA_Family_Child, sec_menus[SEC_BOTH]     = MenuitemObject, MUIA_Menuitem_Title,security[SEC_BOTH]    , MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x37, MUIA_UserData,WMEN_SECUR3, End,
  2101.                   MUIA_Family_Child, sec_menus[SEC_SENDANON] = MenuitemObject, MUIA_Menuitem_Title,security[SEC_SENDANON], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x2F, MUIA_UserData,WMEN_SECUR4, End,
  2102.                   MUIA_Family_Child, sec_menus[SEC_DEFAULTS] = MenuitemObject, MUIA_Menuitem_Title,security[SEC_DEFAULTS], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x1F, MUIA_UserData,WMEN_SECUR5, MUIA_Menuitem_Checked, TRUE, End,
  2103.                End,
  2104.             End,
  2105.          End,
  2106.          MUIA_Window_AppWindow, TRUE,
  2107.          WindowContents, VGroup,
  2108.             Child, data->GUI.RG_PAGE = RegisterGroup(rtitles),
  2109.                MUIA_CycleChain, 1,
  2110.                Child, VGroup, /* Message */
  2111.                   MUIA_HelpNode, "WR00",
  2112.                   Child, ColGroup(2),
  2113.                      Child, Label(GetStr(MSG_WR_To)),
  2114.                      Child, MakeAddressField(&data->GUI.ST_TO, GetStr(MSG_WR_To), MSG_HELP_WR_ST_TO, ABM_TO, winnum, TRUE),
  2115.                      Child, Label(GetStr(MSG_WR_Subject)),
  2116.                      Child, data->GUI.ST_SUBJECT = MakeString(SIZE_SUBJECT,GetStr(MSG_WR_Subject)),
  2117.                   End,
  2118.                   Child, (C->HideGUIElements & HIDE_TBAR) ?
  2119.                      (RectangleObject, MUIA_ShowMe, FALSE, End) :
  2120.                      (HGroup, GroupSpacing(0),
  2121.                         Child, HGroupV,
  2122.                            Child, data->GUI.TO_TOOLBAR = ToolbarObject,
  2123.                               MUIA_Toolbar_ImageType,      MUIV_Toolbar_ImageType_File,
  2124.                               MUIA_Toolbar_ImageNormal,    "PROGDIR:Icons/Write.toolbar",
  2125.                               MUIA_Toolbar_ImageGhost,     "PROGDIR:Icons/Write_G.toolbar",
  2126.                               MUIA_Toolbar_ImageSelect,    "PROGDIR:Icons/Write_S.toolbar",
  2127.                               MUIA_Toolbar_Description,    data->GUI.TB_TOOLBAR,
  2128.                               MUIA_Font,                   MUIV_Font_Tiny,
  2129.                               MUIA_ShortHelp, TRUE,
  2130.                            End,
  2131.                            Child, HSpace(0),
  2132.                         End,
  2133.                         Child, (C->HideGUIElements & HIDE_XY) ?
  2134.                            HSpace(1) :
  2135.                            (VCenter((data->GUI.TX_POSI = TextObject,
  2136.                               TextFrame,
  2137.                               MUIA_Weight    ,0,
  2138.                               MUIA_Text_Contents, "000\n000",
  2139.                               MUIA_Background,MUII_TextBack,
  2140.                               MUIA_Frame     ,MUIV_Frame_Text,
  2141.                               MUIA_Font      ,MUIV_Font_Tiny,
  2142.                            End))),
  2143.                      End),
  2144.                   Child, HGroup,
  2145.                      MUIA_HelpNode, "EDIT",
  2146.                      MUIA_Group_Spacing, 0,
  2147.                      Child, data->GUI.TE_EDIT = NewObject(CL_TextEditor->mcc_Class,NULL,
  2148.                         InputListFrame,
  2149.                         MUIA_TextEditor_Slider, slider,
  2150.                         MUIA_TextEditor_ColorMap, G->EdColMap,
  2151.                         MUIA_TextEditor_FixedFont, C->FixedFontEdit,
  2152.                         MUIA_TextEditor_WrapBorder, C->EdWrapMode == 1 ? C->EdWrapCol : 0,
  2153.                         MUIA_TextEditor_ExportWrap, C->EdWrapMode == 2 ? C->EdWrapCol : 0,
  2154.                         MUIA_TextEditor_ImportHook, MUIV_TextEditor_ImportHook_EMail,
  2155.                         MUIA_TextEditor_ExportHook, MUIV_TextEditor_ExportHook_EMail,
  2156.                         MUIA_CycleChain, TRUE,
  2157.                      End,
  2158.                      Child, slider,
  2159.                   End,
  2160.                End,
  2161.                Child, VGroup, /* Attachments */
  2162.                   MUIA_HelpNode, "WR01",
  2163.                   Child, NListviewObject,
  2164.                      MUIA_CycleChain, 1,
  2165.                      MUIA_Listview_DragType, 1,
  2166.                      MUIA_NListview_NList,         data->GUI.LV_ATTACH = NewObject(CL_AttachList->mcc_Class,NULL,
  2167.                         InputListFrame,
  2168.                         MUIA_NList_ListBackground, MUII_ListBack,
  2169.                         MUIA_NList_TitleBackground, MUII_ListBack,
  2170.                         MUIA_NList_DragSortable ,TRUE,
  2171.                         MUIA_NList_Format       ,"D=8 BAR,P=\033r D=8 BAR,D=8 BAR,P=\033c D=8 BAR,",
  2172.                         MUIA_NList_Title        ,TRUE,
  2173.                         MUIA_NList_ConstructHook,&WR_LV_ConFuncHook,
  2174.                         MUIA_NList_DestructHook ,&GeneralDesHook,
  2175.                         MUIA_NList_DisplayHook  ,&WR_LV_DspFuncHook,
  2176.                      End,
  2177.                   End,
  2178.                   Child, ColGroup(4),
  2179.                      Child, data->GUI.BT_ADD     = MakeButton(GetStr(MSG_WR_Add)),
  2180.                      Child, data->GUI.BT_ADDPACK = MakeButton(GetStr(MSG_WR_AddPack)),
  2181.                      Child, data->GUI.BT_DEL     = MakeButton(GetStr(MSG_Del)),
  2182.                      Child, data->GUI.BT_DISPLAY = MakeButton(GetStr(MSG_WR_Display)),
  2183.                   End,
  2184.                   Child, HGroup,
  2185.                      Child, data->GUI.RA_ENCODING = RadioObject,
  2186.                         GroupFrameT(GetStr(MSG_WR_Encoding)),
  2187.                         MUIA_Radio_Entries, encoding,
  2188.                         MUIA_CycleChain, 1,
  2189.                      End,
  2190.                      Child, ColGroup(2),
  2191.                         Child, Label2(GetStr(MSG_WR_ContentType)),
  2192.                         Child, PoplistObject,
  2193.                            MUIA_Popstring_String, data->GUI.ST_CTYPE = MakeString(SIZE_CTYPE,GetStr(MSG_WR_ContentType)),
  2194.                            MUIA_Popstring_Button, PopButton(MUII_PopUp),
  2195.                            MUIA_Poplist_Array   , ContType,
  2196.                         End,
  2197.                         Child, Label2(GetStr(MSG_WR_Description)),
  2198.                         Child, data->GUI.ST_DESC = MakeString(SIZE_DEFAULT,GetStr(MSG_WR_Description)),
  2199.                         Child, HSpace(0),
  2200.                      End,
  2201.                   End,
  2202.                End,
  2203.                Child, VGroup, /* Options */
  2204.                   MUIA_HelpNode, "WR02",
  2205.                   Child, ColGroup(2),
  2206.                      Child, Label(GetStr(MSG_WR_CopyTo)),
  2207.                      Child, MakeAddressField(&data->GUI.ST_CC, GetStr(MSG_WR_CopyTo), MSG_HELP_WR_ST_CC, ABM_CC, winnum, TRUE),
  2208.                      Child, Label(GetStr(MSG_WR_BlindCopyTo)),
  2209.                      Child, MakeAddressField(&data->GUI.ST_BCC, GetStr(MSG_WR_BlindCopyTo), MSG_HELP_WR_ST_BCC, ABM_BCC, winnum, TRUE),
  2210.                      Child, Label(GetStr(MSG_WR_From)),
  2211.                      Child, MakeAddressField(&data->GUI.ST_FROM, GetStr(MSG_WR_From), MSG_HELP_WR_ST_FROM, ABM_FROM, winnum, FALSE),
  2212.                      Child, Label(GetStr(MSG_WR_ReplyTo)),
  2213.                      Child, MakeAddressField(&data->GUI.ST_REPLYTO, GetStr(MSG_WR_ReplyTo), MSG_HELP_WR_ST_REPLYTO, ABM_REPLYTO, winnum, FALSE),
  2214.                      Child, Label(GetStr(MSG_WR_ExtraHeaders)),
  2215.                      Child, data->GUI.ST_EXTHEADER = MakeString(SIZE_LARGE,GetStr(MSG_WR_ExtraHeaders)),
  2216.                   End,
  2217.                   Child, HGroup,
  2218.                      Child, VGroup, GroupFrameT(GetStr(MSG_WR_SendOpt)),
  2219.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_DELSEND, GetStr(MSG_WR_DelSend)),
  2220.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_RECEIPT, GetStr(MSG_WR_Receipt)),
  2221.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_DISPNOTI, GetStr(MSG_WR_GetMDN)),
  2222.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_ADDINFO, GetStr(MSG_WR_AddInfo)),
  2223.                         Child, HGroup,
  2224.                            Child, Label(GetStr(MSG_WR_Importance)),
  2225.                            Child, data->GUI.CY_IMPORTANCE = MakeCycle(priority, GetStr(MSG_WR_Importance)),
  2226.                         End,
  2227.                      End,
  2228.                      Child, HSpace(0),
  2229.                      Child, data->GUI.RA_SIGNATURE = RadioObject, GroupFrameT(GetStr(MSG_WR_Signature)),
  2230.                         MUIA_Radio_Entries, signat,
  2231.                         MUIA_Radio_Active, C->UseSignature ? 1 : 0,
  2232.                         MUIA_CycleChain, 1,
  2233.                      End,
  2234.                      Child, HSpace(0),
  2235.                      Child, data->GUI.RA_SECURITY = RadioObject, GroupFrameT(GetStr(MSG_WR_Security)),
  2236.                            MUIA_Radio_Entries, security,
  2237.                            MUIA_Radio_Active, SEC_DEFAULTS,
  2238.                            MUIA_CycleChain, 1,
  2239.                         End,
  2240.                   End,
  2241.                End,
  2242.             End,
  2243.             Child, ColGroup(4),
  2244.                Child, data->GUI.BT_SEND   = MakeButton(GetStr(MSG_WR_Send)),
  2245.                Child, data->GUI.BT_QUEUE  = MakeButton(GetStr(MSG_WR_ToQueue)),
  2246.                Child, data->GUI.BT_HOLD   = MakeButton(GetStr(MSG_WR_Hold)),
  2247.                Child, data->GUI.BT_CANCEL = MakeButton(GetStr(MSG_Cancel)),
  2248.             End,
  2249.          End,
  2250.       End;
  2251.       if (data->GUI.WI)
  2252.       {
  2253.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  2254.          set(data->GUI.ST_TO, MUIA_UserData, data->GUI.ST_SUBJECT);
  2255.          set(data->GUI.ST_CC, MUIA_UserData, data->GUI.ST_BCC);
  2256.          set(data->GUI.ST_BCC, MUIA_UserData, data->GUI.ST_FROM);
  2257.          set(data->GUI.ST_FROM, MUIA_UserData, data->GUI.ST_REPLYTO);
  2258.          set(data->GUI.ST_REPLYTO, MUIA_UserData, data->GUI.ST_EXTHEADER);
  2259.          get(data->GUI.TE_EDIT, MUIA_TextEditor_TypeAndSpell, &spell);
  2260.          set(mi_autospell, MUIA_Menuitem_Checked, spell);
  2261.          set(data->GUI.CY_IMPORTANCE, MUIA_Cycle_Active, 1);
  2262.          DoMethod(G->App, MUIM_MultiSet,  MUIA_Disabled, TRUE, data->GUI.RA_ENCODING, data->GUI.ST_CTYPE, data->GUI.ST_DESC, data->GUI.BT_DEL, data->GUI.BT_DISPLAY, NULL);
  2263.          SetHelp(data->GUI.ST_SUBJECT    ,MSG_HELP_WR_ST_SUBJECT   );
  2264.          SetHelp(data->GUI.BT_ADD        ,MSG_HELP_WR_BT_ADD       );
  2265.          SetHelp(data->GUI.BT_ADDPACK    ,MSG_HELP_WR_BT_ADDPACK   );
  2266.          SetHelp(data->GUI.BT_DEL        ,MSG_HELP_WR_BT_DEL       );
  2267.          SetHelp(data->GUI.BT_DISPLAY    ,MSG_HELP_WR_BT_DISPLAY   );
  2268.          SetHelp(data->GUI.RA_ENCODING   ,MSG_HELP_WR_RA_ENCODING  );
  2269.          SetHelp(data->GUI.ST_CTYPE      ,MSG_HELP_WR_ST_CTYPE     );
  2270.          SetHelp(data->GUI.ST_DESC       ,MSG_HELP_WR_ST_DESC      );
  2271.          SetHelp(data->GUI.ST_EXTHEADER  ,MSG_HELP_WR_ST_EXTHEADER );
  2272.          SetHelp(data->GUI.CH_DELSEND    ,MSG_HELP_WR_CH_DELSEND   );
  2273.          SetHelp(data->GUI.CH_RECEIPT    ,MSG_HELP_WR_CH_RECEIPT   );
  2274.          SetHelp(data->GUI.CH_DISPNOTI   ,MSG_HELP_WR_CH_DISPNOTI  );
  2275.          SetHelp(data->GUI.CH_ADDINFO    ,MSG_HELP_WR_CH_ADDINFO   );
  2276.          SetHelp(data->GUI.CY_IMPORTANCE ,MSG_HELP_WR_CY_IMPORTANCE);
  2277.          SetHelp(data->GUI.RA_SIGNATURE  ,MSG_HELP_WR_RA_SIGNATURE );
  2278.          SetHelp(data->GUI.RA_SECURITY   ,MSG_HELP_WR_RA_SECURITY  );
  2279.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_NEW       ,data->GUI.TE_EDIT      ,1,MUIM_TextEditor_ClearText);
  2280.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_OPEN      ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_OPEN,winnum);
  2281.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSFILE   ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSERT,winnum);
  2282.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSQUOT   ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSQUOT,winnum);
  2283.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSALTQUOT,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSALTQUOT,winnum);
  2284.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSROT13  ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSROT13,winnum);
  2285.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_SAVEAS    ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_SaveAsHook,winnum);
  2286.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_EDIT      ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_EditHook,winnum);
  2287.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_CUT       ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Cut");
  2288.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_COPY      ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Copy");
  2289.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASTE     ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Paste");
  2290.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASQUOT   ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_PASQUOT,winnum);
  2291.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASALTQUOT,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_PASALTQUOT,winnum);
  2292.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASROT13  ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_PASROT13,winnum);
  2293.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_DICT      ,MUIV_Notify_Application,3,MUIM_CallHook   ,&DI_OpenHook,winnum);
  2294.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_UNDO      ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Undo");
  2295.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_REDO      ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Redo");
  2296.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_ADDFILE   ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddFileHook,winnum);
  2297.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_ADDCLIP   ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddClipboardHook,winnum);
  2298.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_ADDPGP    ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddPGPKeyHook,winnum);
  2299.          for (i = 0; i < 4; i++) DoMethod(data->GUI.WI,MUIM_Notify,MUIA_Window_MenuAction,WMEN_EMOT0+i,data->GUI.TE_EDIT,2,MUIM_TextEditor_InsertText,emoticons[i]);
  2300.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_SEP0      ,data->GUI.TE_EDIT      ,4,MUIM_CallHook   ,&WR_InsertSeparatorHook,FALSE,winnum);
  2301.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_SEP1      ,data->GUI.TE_EDIT      ,4,MUIM_CallHook   ,&WR_InsertSeparatorHook,TRUE,winnum);
  2302.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_AppMessage          ,MUIV_EveryTime ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_AppHook,MUIV_TriggerValue,winnum);
  2303.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_AreaMarked,MUIV_EveryTime,MUIV_Notify_Application,5,MUIM_MultiSet  ,MUIA_Menuitem_Enabled,MUIV_TriggerValue,mi_copy,mi_cut,NULL);
  2304.          if (data->GUI.TO_TOOLBAR)
  2305.          {
  2306.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_AreaMarked,MUIV_EveryTime,data->GUI.TO_TOOLBAR  ,6,MUIM_Toolbar_MultiSet,MUIV_Toolbar_Set_Ghosted, MUIV_NotTriggerValue,3,4,-1);
  2307.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_UndoAvailable,MUIV_EveryTime,data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,6,MUIV_Toolbar_Set_Ghosted,MUIV_NotTriggerValue);
  2308.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 0, MUIV_Toolbar_Notify_Pressed,FALSE, MUIV_Notify_Application,3,MUIM_CallHook,&WR_EditHook,winnum);
  2309.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 1, MUIV_Toolbar_Notify_Pressed,FALSE, MUIV_Notify_Application,4,MUIM_CallHook,&WR_EditorCmdHook,ED_INSERT,winnum);
  2310.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 3, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "CUT");
  2311.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 4, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "COPY");
  2312.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 5, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "PASTE");
  2313.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 6, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "UNDO");
  2314.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 8, MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleBold,     MUIV_TriggerValue);
  2315.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 9, MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleItalic,   MUIV_TriggerValue);
  2316.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,10, MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleUnderline,MUIV_TriggerValue);
  2317.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,11, MUIV_Toolbar_Notify_Pressed,TRUE,           data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           7);
  2318.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,11, MUIV_Toolbar_Notify_Pressed,FALSE,          data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           0);
  2319.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleBold,      MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 8,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2320.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleItalic,    MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 9,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2321.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleUnderline, MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,10,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2322.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            7,              data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,11,MUIV_Toolbar_Set_Selected,TRUE);
  2323.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            0,              data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,11,MUIV_Toolbar_Set_Selected,FALSE);
  2324.             DoMethod(mi_bold              ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 8,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2325.             DoMethod(mi_italic            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 9,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2326.             DoMethod(mi_underl            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,10,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2327.             DoMethod(mi_color             ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,11,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2328.          }
  2329.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_UndoAvailable,MUIV_EveryTime,mi_undo            ,3,MUIM_Set,MUIA_Menuitem_Enabled,MUIV_TriggerValue);
  2330.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_RedoAvailable,MUIV_EveryTime,mi_redo            ,3,MUIM_Set,MUIA_Menuitem_Enabled,MUIV_TriggerValue);
  2331.          if (data->GUI.TX_POSI)
  2332.          {
  2333.             DoMethod(data->GUI.TE_EDIT ,MUIM_Notify,MUIA_TextEditor_CursorX,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook,&WR_UpdateWTitleHook,winnum);
  2334.             DoMethod(data->GUI.TE_EDIT ,MUIM_Notify,MUIA_TextEditor_CursorY,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook,&WR_UpdateWTitleHook,winnum);
  2335.          }
  2336.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleBold,      MUIV_EveryTime, mi_bold        ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2337.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleItalic,    MUIV_EveryTime, mi_italic      ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2338.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleUnderline, MUIV_EveryTime, mi_underl      ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2339.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            7,              mi_color       ,3,MUIM_Set        ,MUIA_Menuitem_Checked,TRUE);
  2340.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            0,              mi_color       ,3,MUIM_Set        ,MUIA_Menuitem_Checked,FALSE);
  2341.          DoMethod(mi_bold              ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleBold,     MUIV_TriggerValue);
  2342.          DoMethod(mi_italic            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleItalic,   MUIV_TriggerValue);
  2343.          DoMethod(mi_underl            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleUnderline,MUIV_TriggerValue);
  2344.          DoMethod(mi_color             ,MUIM_Notify, MUIA_Menuitem_Checked,          TRUE,           data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           7);
  2345.          DoMethod(mi_color             ,MUIM_Notify, MUIA_Menuitem_Checked,          FALSE,          data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           0);
  2346.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_Group_ActivePage    ,0             ,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_NoMenus,FALSE);
  2347.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_Group_ActivePage    ,1             ,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_NoMenus,TRUE);
  2348.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_Group_ActivePage    ,2             ,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_NoMenus,TRUE);
  2349.          DoMethod(data->GUI.ST_SUBJECT ,MUIM_Notify,MUIA_String_Acknowledge  ,MUIV_EveryTime,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_ActiveObject,data->GUI.TE_EDIT);
  2350.          DoMethod(data->GUI.BT_ADD     ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddFileHook,winnum);
  2351.          DoMethod(data->GUI.BT_ADDPACK ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddArchiveHook,winnum);
  2352.          DoMethod(data->GUI.BT_DEL     ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,data->GUI.LV_ATTACH    ,2,MUIM_List_Remove,MUIV_List_Remove_Active);
  2353.          DoMethod(data->GUI.BT_DISPLAY ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,data->GUI.LV_ATTACH    ,3,MUIM_CallHook   ,&WR_DisplayFileHook,winnum);
  2354.          DoMethod(data->GUI.LV_ATTACH  ,MUIM_Notify,MUIA_List_Active         ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_GetFileEntryHook,winnum);
  2355.          DoMethod(data->GUI.RA_ENCODING,MUIM_Notify,MUIA_Radio_Active        ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_PutFileEntryHook,winnum);
  2356.          DoMethod(data->GUI.ST_CTYPE   ,MUIM_Notify,MUIA_String_Contents     ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_PutFileEntryHook,winnum);
  2357.          DoMethod(data->GUI.ST_DESC    ,MUIM_Notify,MUIA_String_Contents     ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_PutFileEntryHook,winnum);
  2358.          DoMethod(data->GUI.RA_SIGNATURE,MUIM_Notify,MUIA_Radio_Active        ,MUIV_EveryTime,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_ChangeSignatureHook,MUIV_TriggerValue,winnum);
  2359.          DoMethod(data->GUI.CH_DELSEND ,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_delsend              ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2360.          DoMethod(data->GUI.CH_RECEIPT ,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_receipt              ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2361.          DoMethod(data->GUI.CH_DISPNOTI,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_dispnoti             ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2362.          DoMethod(data->GUI.CH_ADDINFO ,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_addinfo              ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2363.          DoMethod(mi_autospell         ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.TE_EDIT       ,3,MUIM_Set        ,MUIA_TextEditor_TypeAndSpell,MUIV_TriggerValue);
  2364.          DoMethod(mi_delsend           ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_DELSEND    ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2365.          DoMethod(mi_receipt           ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_RECEIPT    ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2366.          DoMethod(mi_dispnoti          ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_DISPNOTI   ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2367.          DoMethod(mi_addinfo           ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_ADDINFO    ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2368.          DoMethod(data->GUI.RA_SECURITY,MUIM_Notify,MUIA_Radio_Active        ,4             ,data->GUI.RA_SIGNATURE  ,3,MUIM_Set        ,MUIA_Radio_Active,0);
  2369.          DoMethod(data->GUI.RA_SECURITY,MUIM_Notify,MUIA_Radio_Active        ,4             ,data->GUI.CH_ADDINFO    ,3,MUIM_Set        ,MUIA_Selected,FALSE);
  2370.          for (i = 0; i < 3; i++)
  2371.          {
  2372.             DoMethod(data->GUI.CY_IMPORTANCE,MUIM_Notify,MUIA_Cycle_Active     ,i              ,strip                  ,4,MUIM_SetUData,WMEN_IMPORT0+i,MUIA_Menuitem_Checked,TRUE);
  2373.             DoMethod(data->GUI.WI           ,MUIM_Notify,MUIA_Window_MenuAction,WMEN_IMPORT0+i ,data->GUI.CY_IMPORTANCE,3,MUIM_Set     ,MUIA_Cycle_Active,i);
  2374.          }
  2375.          for (i = 0; i < 4; i++) 
  2376.          {
  2377.             DoMethod(data->GUI.RA_SIGNATURE ,MUIM_Notify,MUIA_Radio_Active     ,i              ,strip                  ,4,MUIM_SetUData,WMEN_SIGN0+i,MUIA_Menuitem_Checked,TRUE);
  2378.             DoMethod(data->GUI.WI           ,MUIM_Notify,MUIA_Window_MenuAction,WMEN_SIGN0+i   ,data->GUI.RA_SIGNATURE ,3,MUIM_Set     ,MUIA_Radio_Active,i);
  2379.          }
  2380.          for (i = SEC_NONE; i < SEC_MAXDUMMY; i++) 
  2381.          {
  2382.                 // connect menuitems -> radiobuttons
  2383.                 DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction,WMEN_SECUR0+i,data->GUI.RA_SECURITY,3,MUIM_Set        ,MUIA_Radio_Active    ,i);
  2384.                 // ...and the other way round
  2385.                 DoMethod(data->GUI.RA_SECURITY,MUIM_Notify,MUIA_Radio_Active     ,i            ,sec_menus[i]         ,3,MUIM_NoNotifySet,MUIA_Menuitem_Checked,TRUE);
  2386.          }
  2387.          WR_SharedSetup(data, winnum);
  2388.          return data;
  2389.       }
  2390.       free(data);
  2391.    }
  2392.    return NULL;
  2393. }
  2394.  
  2395. ///
  2396. /// WR_NewBounce
  2397. //  Creates a bounce window
  2398. LOCAL struct WR_ClassData *WR_NewBounce(int winnum)
  2399. {
  2400.    struct WR_ClassData *data;
  2401.  
  2402.    if ((data = calloc(1,sizeof(struct WR_ClassData))))
  2403.    {
  2404.       data->GUI.WI = WindowObject,
  2405.          MUIA_Window_Title, GetStr(MSG_WR_BounceWT),
  2406.          MUIA_HelpNode, "WR_W",
  2407.          MUIA_Window_ID, MAKE_ID('W','R','I','B'),
  2408.          WindowContents, VGroup, GroupFrame,
  2409.             MUIA_Background, MUII_GroupBack,
  2410.             Child, ColGroup(2),
  2411.                Child, Label2(GetStr(MSG_WR_BounceTo)),
  2412.                Child, MakeAddressField(&data->GUI.ST_TO, GetStr(MSG_WR_BounceTo), MSG_HELP_WR_ST_TO, ABM_TO, winnum, TRUE),
  2413.             End,
  2414.             Child, ColGroup(4),
  2415.                Child, data->GUI.BT_SEND   = MakeButton(GetStr(MSG_WR_Send)),
  2416.                Child, data->GUI.BT_QUEUE  = MakeButton(GetStr(MSG_WR_ToQueue)),
  2417.                Child, data->GUI.BT_HOLD   = MakeButton(GetStr(MSG_WR_Hold)),
  2418.                Child, data->GUI.BT_CANCEL = MakeButton(GetStr(MSG_Cancel)),
  2419.             End,
  2420.          End,
  2421.       End;
  2422.       if (data->GUI.WI)
  2423.       {
  2424.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  2425.          set(data->GUI.ST_TO, MUIA_UserData, data->GUI.BT_SEND);
  2426.          WR_SharedSetup(data, winnum);
  2427.          return data;
  2428.       }
  2429.       free(data);
  2430.    }
  2431.    return NULL;
  2432. }
  2433. /// vi: set ts=3 ss=0 scs si nu:
  2434.